Here are examples of new features in ECMAScript 2016, 2017, and 2018

The original link

It’s hard to keep track of new features in JavaScript(ECMAScript), and even harder to find useful code examples.

Therefore, in this article, I will introduce all 18 features listed in the completed proposal for TC39 added in ES2016, ES2017, and ES2018 (final draft), and show them useful examples.

This is a fairly long post, but should be a simple read. Think of it as Netflix binge reading. After that, I guarantee you’ll know a lot about these features.

Let’s look at them one by one:

ECMAScript 2016

Includes is a simple instance method on arrays and makes it easy to find if an item is in an Array (including NaN unlike indexOf)

const arr = [ 1, 2, 3, 4, NaN];



// Es2016 is not used

if(arr.indexOf(3) >= 0){

console.log(true);

}



/ / use

if(arr.includes(3)){

console.log(true);

}



//ps: Note that indexOf does not support finding nans

arr.includes(NaN) // true

Arr.indexof (NaN) // -1 (indexOf does not support NaN)

Copy the code

Trivia: People want to name the JavaScript specification contains, but this is obviously already used by Mootools, so they use includes.

  • 2. Exponential operators

Mathematical operations such as addition and subtraction have + and – operators respectively. Like them, the ** operator is usually used for exponential operations. ** was introduced in ECMAScript 2016 instead of math.pow.

/ / no use

(7, 2) / / 49 math.h pow



/ / use

7 * * 2 / / 49

Copy the code

ECMAScript 2017

  • 1. Object.values()

Object.value() is a new function similar to Object.keys(), but returns all values of Object’s own properties, excluding any values in the prototype chain.

const cars = { 'BMW': 3, 'Tesla': 2, 'Toyota': 1 };



//ES2015

/ / ES2017 don't use

const vals = Object.keys(cars).map(key => cars[key]);

console.log(vals); / / [3, 2, 1)





/ / ES2017 and the future

/ / use

const values = Object.values(cars);

console.log(values); / / [3, 2, 1)

Copy the code

Object.entries() is related to object.keys, but instead of just returning keys, it returns keys and values as an array. This makes it easy to do things like use objects in loops or convert objects to Maps.

Case 1:

const cars = { 'BMW': 3, 'Tesla': 2, 'Toyota': 1 };

/ / ES5.1

// Instead of extracting keys and then recycling

Object.keys(cars).forEarch(function(key) {

console.log('key: ' + key + 'value: ' + cars[key]);

})



//ES2017 (ES8)

/ / use Object. Entries

for(let [key value] of Object.entries(cars)) {

console.log(`key: ${key} value: ${value}`);

}

Copy the code

Example 2:

const cars = { 'BMW': 3, 'Tesla': 2, 'Toyota': 1 };



//ES2015

/ / no use

// Get the object key, then add each item to map in the loop



const maps = new Map();

Object.keys(cars).forEarch(key => {

map1.set(key, cars[key]);

})



console.log(map1) // Map { 'BMW' => 3, 'Tesla' => 2, 'Toyota' => 1}



/ / ES2017 and later

/ / use

const map = new Map(Object.entries(cars));



console.log(map) //Map { 'BMW' => 3, 'Tesla' => 2, 'Toyota' => 1}

Copy the code
  • 3. String padding

To the String, the String. The prototype. PadStart and String prototype. PadEnd added two instance methods – they allow additional/at the end of the beginning of the original String or add an empty String or other String in advance.

'someString'.padStart(numberOfCharcters [,stringForPadding]); 

'5'.padStart(10) // ' 5'

'5'.padStart(10, '=*') //'=*=*=*=*=5'

'5'.padEnd(10) // '5 '

'5'.padEnd(10, '=*') //'5=*=*=*=*='

Copy the code

This comes in handy when we want to align things in scenarios such as a nice print display or terminal print.

//ES2017

// If you have a list of items of different lengths and want to format their display purpose, you can use padStart



const formatted = [0, 1, 12, 123, 1234, 12345].map(num =>

Num.tostring ().padstart (10, '0') // Add 0 until the length is 10

);



console.log(formatted);



/ / print

/ / /

/ / '0000000000',

/ / '0000000001',

/ / '0000000012',

/ / '0000000123',

/ / '0000001234',

/ / '0000012345',

// ]

Copy the code
  • 3.2 padEnd example:

PadEnd is really handy when we print multiple items of different lengths and want to align them properly.

The following example is a good example of how padEnd, padStart and object. entries can be aggregated to produce beautiful output.

const cars = {

'🚙 BMW' : '10',

'🚘 Tesla', '5',

'🚖 Lamborghini' : '0'

}

Object.entries(cars).map(([name, count]) => {

//padEnd appends ' -' until the name becomes 20 characters

//padStart prepends '0' until the count becomes 3 characters.

console.log(`${name.padEnd(20, ' -')} Count: ${count.padStart(3, '0')}`)

});

// Print the result..

// 🚙BMW - - - - - - - Count: 010

// 🚘Tesla - - - - - - Count: 005

// 🚖Lamborghini -- Count: 000

Copy the code

Emojis and other double-byte characters are represented using multiple bytes of Unicode. So padStart and padEnd may not work as expected! ⚠ ️

For example: Suppose we’re trying to populate the string heart with the ❤️ emoji to reach 10 characters. The results are shown below

// Note, not 5 hearts, only 2 hearts and 1 strange-looking heart!



'heart'. PadStart (10, "❤ ️"); // prints.. '❤ ️ ❤ ️ ❤ heart'

Copy the code

This is because ❤️ is 2 characters long (‘\u2764\uFE0F’)! The word heart itself is five characters, so we are left with five characters. So,JS fills two hearts with ‘\u2764\uFE0F’ and produces ❤️❤️. For the last one just use the mind’s first byte \ u2764 to generate ❤

So the result is: ❤️❤️❤heart

PS: You can use this link to view Unicode character conversions

  • 4. Object.getOwnPropertyDescriptors

This method returns all the details of all the properties of a given object (including the get set method). The main motivation for adding this is to allow a shallow copy/clone of an Object into another Object that also copies getter and setter functions instead of object.assign

Object.assign Shallow clone all details except getter and setter functions for the original source Object.

The following example shows the Object. The Object and assign. GetOwnPropertyDescriptors and Object. The difference between defineProperties, Car to the original Object is copied to the new ElectricCar Object, Object. GetOwnPropertyDescriptors see, discount getter and setter function has also been copied to the target Object.

Before the # # # # # #…

/ / before...

var Car = {

name: 'BMW',

price: 1000000,

set discount(x) {

this.d = x;

},

get discount() {

return this.d;

},

};



// Prints details of the "discount" property of the Car object

console.log(Object.getOwnPropertyDescriptor(Car, 'discount'));

// Print the result..

/ / {

// get: [Function: get],

// set: [Function: set],

// enumerable: true,

// configurable: true

// }



// Copy the attributes of Car to ElectricCar using object. assign

Const ElectricCar = object. assign({}, Car);



// Prints details of the "discount" property of the ElectricCar object

console.log(Object.getOwnPropertyDescriptor(ElectricCar, 'discount'));



/ / print

/ / {

// value: undefined,

// writable: true,

// enumerable: true,

// configurable: true

// }



//⚠️ Notice the lack of getters and setters in the 'discount' property of ElectricCar! 👎 👎

Copy the code

After the # # # # # #…

/ / since...

var Car = {

name: 'BMW',

price: 1000000,

set discount(x) {

this.d = x;

},

get discount() {

return this.d;

},

};

// Copy the attributes of Car to ElectricCar2 using object.defineProperties

/ / and use Object. GetOwnPropertyDescriptors extracting the attribute of the Car



const ElectricCar2 = Object.defineProperties({}, Object.getOwnPropertyDescriptors(Car));

// Prints details of the ElectricCar2 object's "discount" property

console.log(Object.getOwnPropertyDescriptor(ElectricCar2, 'discount'));

//prints..

// {get: [Function: get], 👈🏼👈🏼 port

// set: [Function: set], 👈🏼👈🏼 port

// enumerable: true,

// configurable: true

// }

// Notice that getters and setters exist in ElectricCar2 for the 'discount' property!

Copy the code

This is a small update that allows us to put a trailing comma after the last function argument. Why is that? To help a tool like Git only leaves new developers to blame.

The following example shows the problem and solution:

/ / the problem



// #1 created by the developer

function Person(

name,

age

) {

this.name = name;

this.age = age;

}



//#2 developer adds address

function Person(

name,

Age, // Add trailing comma <-------- Because of commas, developers are warned by tools like git

Address // Add a new parameter

) {

this.name = name;

this.age = age;

this.address = address; // Add the line

}



/ / ES2017 solution

Allow #1 developers to add trailing commas

//#1 is created as follows

function Person(

name,

Ange, //<------- #2 developers do not need to change this line due to trailing commas

) {

this.name = name;

this.age = age;

}

Copy the code

Note: You can also use trailing commas to call functions

  • 6. Async/Await

If you ask me, this is by far the most important and useful feature. Async lets us not deal with call hell and makes the whole code look simple.

The async keyword tells the JavaScript compiler to process functions differently, and the compiler pauses when it reaches the await keyword within the function. It assumes that the expression after await returns a promise and waits for the promise to be resolved or rejected.

In the example below, the getAmount function calls the two asynchronous functions getUser and getBankBalance. We can promise to do this, but it is more elegant and simple to use async await

/ / no use

// ES2015 Promise



function getAmount(userId) {

getUser(userId)

.then(getBankBalance)

.then(amount => {

console.log(amount);

});

}



/ / use...

// ES2017



async function getAmount2(userId) {

var user = await getUser(userId);

var amount = await getBankBalance(user);

console.log(amount);

}



getAmount('1'); / / $1000



getAmount2('1'); / / $1000



function getUser(userId) {

return new Promise(resolve => {

setTimeout(() => {

resolve('john')

}, 1000).

});

}



function getBankBalance(user) {

return new Promise((resolve, reject) => {

setTimeout(() => {

if(user == 'john') {

Resolve (' $1000 ');

} else {

reject(unknown user);

}

}, 1000).

});

}

Copy the code

If you are waiting for the result of an asynchronous function, you need to use Promise’s then syntax to capture its result.

In the following example, we want to log the result using console.log, but not in doubleAndAdd. So we want to wait and pass the result to console.log using the then syntax.



// The asynchronous function itself returns a Promise

async function doubleAndAdd(a, b) {

a = await doubleAfterlSec(a);

b = await doubleAfterlSec(b);

return a + b;

}



/ / usage

doubleAndAdd(1, 2).then(console.log);



function doubleAfterlSec(param) {

return new Promise (resolve => {

setTimeout(resolve(param * 2), 1000);

});

}

Copy the code
  • Calling async/await in parallel

In the previous example, we called wait twice, but each time we waited one second (for a total of two seconds). Instead, we can make it parallel, because A and B don’t depend on other objects that use promise.all.

// The asynchronous function itself returns a Promise

async function doubleAndAdd(a, b) {

// Note: use promise.all here

// Notice the use of array destructuring to capture the results

[a, b] = await Promise.all([doubleAfterlSec(a), doubleAfterlSec(b)]);

return a + b;

}



/ / usage

doubleAndAdd(1, 2).then(console.log);



function doubleAfterlSec(param) {

return new Promise (resolve => {

setTimeout(resolve(param * 2), 1000);

});

}

Copy the code

There are various ways to handle errors when using asynchronous wait below.

Option 1 – Use try catch in functions

// 1. Use try catch



async function doubleAndAdd(a, b) {

try {

a = await doubleAfterlSec(a);

b = await doubleAfterlSec(b);

} catch (e) {

return NaN; // return something

}

return a + b;

}



/ / usage

doubleAndAdd('one', 2).then(console.log) //NaN

doubleAndAdd(1, 2).then(console.log) // 6



function doubleAfterlSec(param) {

return new Promise((resolve, reject) => {

setTimeout(function() {

let val = param * 2;

isNaN(val) > reject(NaN) : resolve(val);

}, 1000);

});

}

Copy the code

Option 2 — Catch every await expression

Since each await expression returns a Promise, you can catch an error on each line, as shown below.

//Option 2 - *Catch* error on each waiting line

// Because each wait expression is itself a Promise

async function doubleAndAdd(a, b) {

a = await doubleAfter1Sec(a).catch(e => console.log('"a" is NaN')); / / 👈

b = await doubleAfter1Sec(b).catch(e => console.log('"b" is NaN')); / / 👈

if (! a || ! b) {

return NaN;

}

return a + b;

}

/ / usage:

doubleAndAdd('one', 2).then(console.log); // NaN and logs: "a" is NaN

doubleAndAdd(1, 2).then(console.log); / / 6

function doubleAfter1Sec(param) {

return new Promise((resolve, reject) => {

setTimeout(function() {

let val = param * 2;

isNaN(val) ? reject(NaN) : resolve(val);

}, 1000);

});

}

Copy the code

Option 3 — Catch the entire async-await function

//Option 3 - Don't do anything, capture outside function

// Because async/wait returns a Promise, we can catch errors in the entire function

async function doubleAndAdd(a, b) {

a = await doubleAfter1Sec(a);

b = await doubleAfter1Sec(b);

return a + b;

}

/ / usage

doubleAndAdd('one', 2)

.then(console.log)

.catch(console.log); / / 👈 👈 🏼 < -- -- -- -- -- -- -- the use "catch"

function doubleAfter1Sec(param) {

return new Promise((resolve, reject) => {

setTimeout(function() {

let val = param * 2;

isNaN(val) ? reject(NaN) : resolve(val);

}, 1000);

});

}

Copy the code

ECMAScript 2018

ECMAScript is currently in its final draft and will be released in June or July 2018. All of the following features are in Stage-4 and will be part of ECMAScript 2018

The main idea is to provide JavaScript with some kind of multithreading capability so that JS developers can write high-performance, concurrent programs by allowing themselves to manage memory rather than having the JS engine manage memory.

This is done with a new type of global object called SharedArrayBuffer, which essentially stores data in a shared memory space. So this data can be shared between the main JS thread and the webworker thread.

Until now, if we wanted to share data between the main JS thread and the Web worker, we had to copy the data and send it to other threads using postMessage. That’s it!

You only need to use SharedArrayBuffer, the main thread, and multiple Web worker threads to access the data.

But sharing memory between threads can lead to a race situation. To avoid race conditions, “Atomics” global objects are introduced. Atomics provides various ways to lock shared memory when a thread is using its data. It also provides a way to securely update data in shared memory.

It is recommended that you use this functionality through a library, but there are no libraries built on top of this functionality.

If you are interested, I recommend reading:

  1. From Workers to Shared Memory — Lucasfcosta
  2. A Cartoon intro to SharedArrayBuffers — Lin Clark
  3. Shared Memory and Atomics — Dr. Axel Rauschmayer
  • 2. Mark template literal restriction removed (template string)

First, we need to clarify what “Tagged Template literal” is so that we can better understand this feature.

In ES2015+, there is a feature called tag template text that allows developers to customize how strings are inserted. For example, insert a string in the standard way, as shown below

// Standard string interpolation

const firstName = 'Raja';

const greetings = `Hello ${firstName}! `;

console.log(greetings); // "Hello Raja!"

Copy the code

In a tag literal, you can write a function that takes a hard-coded part of a string literal, such as [‘Hello’, ‘! ‘] and a replacement variable, such as [‘Raja’], writes it as arguments to a custom function (greet, for example), and then returns whatever you want from that custom function.

The following example shows our custom “Tag” function greet “Good Morning!” , “Good afternoon,” and so on, depending on the time of day of the string text, and returns a custom string.

// The "mark" function returns a custom string literal.

// In this case, greet calls timeGreet () to append Good

/ / Morning/Afternoon/Evening depending on time of day.

function greet(hardCodedPartsArray, ... replacementPartsArray) {

console.log(hardCodedPartsArray); //[ 'Hello ', '!' ]

console.log(replacementPartsArray); //[ 'Raja' ]

let str = '';

hardCodedPartsArray.forEach((string, i) => {

if (i < replacementPartsArray.length) {

str += `${string} ${replacementPartsArray[i] || ''}`;

} else {

str += `${string} ${timeGreet()}`; / / < insert - Good morning/afternoon/evening here

}

});

return str;

}



/ / usage

const firstName = 'Raja';

const greetings = greet`Hello ${firstName}! `; //👈🏼<-- markup text

console.log(greetings); //'Hello Raja! Good Morning!' 🔥

function timeGreet() {

const hr = new Date().getHours();

return hr < 12

? 'Good Morning! '

: hr < 18 ? 'Good Afternoon! ' : 'Good Evening! ';

}

Copy the code

Now that we’ve discussed what the “tag” functionality is, many people want to use this functionality in different domains, such as writing URIs in terminals using commands and HTTP requests, and so on.

⚠️ mark string literal problem

The problem is that the ES2015 and ES2016 specifications do not allow the use of escape characters such as “\u” (Unicode), “\x” (hexadecimal), unless they look exactly like \u00A9 or \uA9A or \xA9.

So if you have a Tagged function that internally uses other domain rules (such as terminal rules), then you might need to use \ubla123abla, which doesn’t look like \ U0049 or \u{@f804}, and you’ll get a syntax error.

In ES2018, just the tag function returns the value in an object with the “cooked” attribute (where the invalid character is “undefined”), and then puts the “raw” attribute (with whatever you want).



function myTagFunc(str) {

return { "cooked": "undefined", "raw": str.raw[0] }

}



var str = myTagFunc `hi \ubla123abla`; / / call myTagFunc



str // { cooked: "undefined", raw: "hi \\unicode" }

Copy the code

Currently in re, although dot (“. ) should match a single character, but it does not match newline characters like \n \r \f.

Such as:

/ / before

/first.second/.test('first\nsecond'); //false

Copy the code

This enhancement enables the dot operator to match any single character. To make sure this doesn’t break anything, we need to use the \ S flag when creating the re to make it work.

//ECMAScript 2018

/first.second/s.test('first\nsecond'); / / true Notice: / s 👈 🏼

Copy the code

Here’s the overall API in the proposal document:

const re = /foo.bar/s;

// const re = new RegExp('foo.bar', 's');



re.test('f00\nbar'); //true

re.dotAll // true

re.flags // 's'

Copy the code
  • 4. RegExp Named Group capture (RegExp Named Group Captures 🔥)

This enhancement provides useful RegExp functionality for other languages (such as Python, Java, etc.) called “named groups.” This feature allows developers to write regexps in different partial formats (? …). Groups in RegExp that provide names (identifiers). They can then use that name to easily get any group they need.

/ / before

let re1 = /(\d{4})-(\d{2})-(\d{2})/;

let result1 = re1.exec('2015-01-02');

console.log(result1);

//

//["2015-01-02", "2015", "01", "02", index: 0, input: "2015-01-02", groups: undefined]



// Later (ES2018)

let re2 = /(? <year>\d{4})-(? <month>\d{2})-(? <day>\d{2})/u;

let result2 = re2.exec('2015-01-02');

console.log(result2);

//["2015-01-02", "2015", "01", "02", index: 0, input: "2015-01-02", groups: { year: '2015', month: '01', day: '02'}]





/ / usage:

// If you want to know the year, you can:



console.log(result2.groups.year) //2015

Copy the code
  • 4.2 Using named groups within the regular expression itself

We can use the \k

format to backreference the group in the regular expression itself. The following example shows how it works.

For example, there is a group called "fruit".

// It matches both "apple" and "orange". We can use "\k<group name>" to refer back and forth to the group result,(\k<fruit>)

// So it matches the same word on both sides of ==

let sameWords = /(? <fruit>apple|orange)==\k<fruit>/u;



sameWords.test('apple==apple'); //true

sameWords.test('orange==orange'); //true

sameWords.test('apple==orange'); //false

Copy the code

Now, the named group functionality is baked into the String’s Replace instance method. So we can easily swap words in strings.

For example, change “firstName, lastName” ==> “lastName, firstName”

// Replace "firstName, lastName" ==> "lastName, firstName"



let re = /(? <firstName>[A-Za-z]+) (? <lastName>[A-Za-z]+$)/u;



'Raja Rao'.replace(re, '$<lastName>, $<firstName>'); // "Rao, Raja"

Copy the code
  • 5. Rest Properties for Objects

Rest operators… (Three points) allow us to extract object attributes that have not yet been extracted.

// Extract firstName and age

// Store the remaining items in the "remaining" variable.



let { fristName, age, ... remaining } = {

fristName: 'john',

lastName: 'smith',

age: 20,

Height: '5.10',

race: 'martian',

};

firstName; //john

age //20

Remaining //{lastName: 'Smith ', height: '5.10', race:' Martian '}

Copy the code
  • 5.2 Even better, you can delete what you don’t need! 🔥 🔥

If we want to remove the SSN, we do not need to traverse the entire object and create a new cleanObj.

// Simply use REST deconstruction to extract the SSN and save the rest in cleanObj.



let { SSN, ... cleanObj } = {

firstName: 'john',

lastName: 'smith',

SSN: '123-45-6789',

race: 'martian',

}



cleanObj; //{ firstName: 'john', lastName: 'smith', race: 'martian' }

Copy the code

Tip: The extension operator is used on the right side of the equal sign. Rest is used on the left side of the equal sign.

// Merge person and account

const person = { fName: 'john', age: 20 };

const account = { name: 'bofa', amount: '$1000' };



// Extract the attributes of person and Account by extending the operator and add them to a new object.

const personAndAccount = { ... person, ... account };

personAndAccount; // {fName: 'john', age: 20, name: 'bofa', amount: '$1000' }

Copy the code
  • 7. The RegExp statement

This is an enhancement to RegExp, which allows us to ensure that certain strings immediately precede others.

You can now use a group (? < =…). (question mark, less than, equal) to find affirmations.

In addition, you can use (? < =…). (question mark, less than, exclamation mark) to view negative statements. Essentially, as long as the -ve declaration passes, it matches.

Positive: Suppose we want to ensure that the # symbol exists before the word winning (i.e., #winning) and that the regular expression returns only the string “winning.” This is how you write it.

/ (? <=#).*/.test('winning'); // false

/ (? <=#).*/.test('#winning'); // true



/ / before

'#winning'.match(/#.*/)[0]; // '#wining', containing #



/ / after ES2018

'#winning'.match(/(? < = #). * /) [0]; // 'wining' has no #, # is used for verification.

Copy the code

Negative declaration: Suppose we want to extract numbers from the line that precedes them with a €sign instead of a $sign.

// 3.00 does not match because the $sign precedes it



'A gallon of milk is $3.00'. Match (/(? <\$)\d+\.? \d+/); // null



// 2.43 Matched successfully because there was no $sign before it

// When matched, no sign €is included

'A gallon of milk is €3.00'. Match (/(? <\$)\d+\.? \d+/)[0]; / / 2.43

Copy the code

It is not easy to write regExps to match various Unicode characters. Items like \w, \w, \d can only match English characters and numbers. But what about numbers in Hindi, Greek and other languages?

This is where Unicode Property Escapes comes in. As a result, Unicode adds a metadata attribute to each symbol (character) and uses it to group or describe various symbols.

For example, the Unicode database combines all Hindi characters (API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API API So we can search Script=Devanagari and get all Hindi characters.

Devanagari(Sanskrit) can be used in Marathi, Hindi, Sanskrit, various Indian languages.

Starting with ECMAScript 2018, we can use \ P escape characters and {Script=Devanagari} to match all Indian characters. That is, we can use: \p{Script=Devanagari} in the RegEx to match all Sanskrit characters.

// He follows to match multiple Hindi characters

/ ^ \ p {Script = Devanagari} + $/ u.t est (' ह ि न ् द ी '); //true

//PS: there are 3 Hindi characters h

Copy the code

Similarly, Unicode databases combine all Greek characters into Script_Extensions (and Script) properties with a value of Greek. So we can use Script_Extensions=Greek or Script=Greek to search for all Greek characters.

That is, we can use it in RegEx:\p{Script = Greek}To match all Greek characters.

// Matches a Greek character below

/ \ p {Script_Extensions = Greek} / u.t est (" PI "); // true

Copy the code

In addition, the Unicode database stores various types of Emojis in Boolean Emojis with the attribute value “true”, Emoji_Component, Emoji_Presentation, Under Emoji_Modifier and Emoji_Modifier_Base. So we can find all the emojis by simply selecting them.

In other words, we can use:\p{Emoji}.\Emoji_ModifierAnd so on to match various Emojis.

The following example will make it clear.

// Here are the matching emoticons

/ \ p {Emoji} / u.t est (' ❤ ️ '); //true

// The following operation failed because yellow emojis do not have Emoji_Modifier!

/ \ p {Emoji} \ p {Emoji_Modifier} / u.t est (' ✌ ️ '); //false

\p{Emoji} is followed by \p{Emoji_Modifier}.

/ \ p {Emoji} \ p {Emoji_Modifier} / u.t est (' ✌ 🏽 '); //true

/ / interpretation:

By default, the victory emoji is yellow. If we use brown, black or other of the same emoticon, they are considered variants of the original emoticon and are represented by two Unicode characters. One is the original emoji and the other is the Unicode character of the color. In the example below, although we only see a brown victory emoji, it actually uses two Unicode characters, one for emoji and one for brown.



// In the Unicode database, these colors have the Emoji_Modifier attribute. Therefore, we need to use \ P {Emoji} and \ P {Emoji_Modifier} to correctly and completely match the brown Emoji.



/ \ p {Emoji} \ p {Emoji_Modifier} / u.t est (' ✌ 🏽 '); //true

Copy the code

Finally, we can negate a match with a capitalized “P” (\P) escape character instead of a small P (\P).

Reference: ECMAScript 2018 Proposal

  • 9. Promise.prototype.finally()

Finally () is the new instance method added to the Promise. His main idea is to allow callbacks to be run after resolution or rejection to help clean things up. The finally callback has no value when called and is always executed anyway.

Let’s look at the scenarios:

// Resolve



let started = true;

let myPromise = new Promise(function(resolve, reject) {

resolve('all good');

})

.then(val => {

console.log(val); //all good

})

.catch(e => {

The console. The log (e) l / / skip

})

.finally(() => {

console.log('This function is always executed! ');

started = false; / / remove

})

Copy the code
// Reject

let started = true;

let myPromise = new Promise(function(resolve, reject) {

resolve('reject apple');

})

.then(val => {

console.log(val); //reject apple

})

.catch(e => {

Console. log(e) L // Catch skipped

})

.finally(() => {

// Notice that there are no values here

console.log('This function is always executed! ');

started = false; / / remove

})

Copy the code
// Error 1

//Promise throws an error





let started = true;

let myPromise = new Promise(function(resolve, reject) {

throw new Error('Error');

})

.then(val => {

console.log(val); / / to skip

})

.catch(e => {

Console. log(e)l // Error catch is invoked

})

.finally(() => {

// Notice that there are no values here

console.log('This function is always executed! ');

started = false; / / remove

})

Copy the code


// An error is thrown from a "catch" event



let started = true;

let myPromise = new Promise(function(resolve, reject) {

throw new Error('something happend');

})

.then(val => {

console.log(val); / / to skip

})

.catch(e => {

throw new Error('throw another error')

})

.finally(() => {

// Notice that there are no values here

console.log('This function is always executed! ');

started = false; / / remove

// Error forms of capture will need to be handled by calling functions elsewhere

})

Copy the code

This is a very useful feature. Basically it allows us to easily create asynchronous code loops!

This feature adds a new “for-await-of” loop that allows us to call asynchronous functions to return promises (or arrays with a series of promises). The cool thing is that the loop waits for each Promise to resolve before the next loop.

const promises = [

new Promise(resolve => resolve(1)),

new Promise(resolve => resolve(2)),

new Promise(resolve => resolve(3)),

]

/ / before

// for-of uses regular synchronous iterators

// Don't wait for Promise to solve



async function test1() {

for (const obj of promise) {

Console. log(obj) // Records three Promise objects

}

}



/ / after

// for-wait-of uses asynchronous iteration



async function test2() {

for await (const obj of promises) {

console.log(obj); / / 1, 2, 3

}

}



test1() // promise, promise, promise

Test2 () / / 1, 2, 3

Copy the code

Author: sachieyuan


  • Links to this article: Blog.rsuitejs.com/2018/04/11/…
  • Copyright Notice: All articles on this blog are licensed under a CC BY-NC-SA 3.0 license unless otherwise stated. Reprint please indicate the source!