New version of ECMAScript feature analysis

1.1 New Features of ES 7 includes is a very useful method on Array, which is used to quickly find whether an element is contained in the array, including NaN (so it is not the same as indexOf).

(() => {
let arr = [1, 2, 3, NaN];
if (arr.includes(2)) {
//Find if 2 exists in the arr array
console.log("Found it!"); //>> Found it!
}
if (!arr.includes(2, 3)) {
//The second parameter 3 represents the item whose array index is 3, that is, the fourth item starts to search
console.warn("does not exist!"); //>> does not exist!
}
//The following two sentences explain the difference between incluedes and indexOf
console.log(arr.includes(NaN)); //true
console.log(arr.indexOf(NaN) != -1); //false
})();

1.2 ES 8 new features Object.values() / Object.entries The usage is Object.values(obj), obj can be an object or an array

const obj = {x:'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]
const obj = ['e','s', '8']; // equivalent to {0:'e', 1:'s', 2: '8' };
Object.values(obj); // ['e','s', '8']
// When the number is used as the key of the object, the returned array is sorted in ascending order of the value of the key
const obj = {10:'xxx', 1:'yyy', 3:'zzz' };
Object.values(obj); // ['yyy','zzz','xxx']
Object.values('es8'); // ['e','s', '8']

The Object.entries method returns an array [key, value] of the enumerable property values ​​of a given object, similar to Object.values.

const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]
const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10', 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]

Asynchronous function Async Functions is what we often call Async/Await. I believe everyone is familiar with this concept. Async/Await is syntactic sugar for processing JS asynchronous operations, which can help us get rid of callback hell and write more elegant code. In popular understanding, the role of the async keyword is to tell the compiler to treat the calibrated function differently. When the compiler encounters the await keyword in the calibrated function, it should temporarily stop running and wait until the await calibrated function is processed before performing the corresponding operation. If the function is fulfilled, the return value is the fulfillment value, otherwise, the rejection value is obtained. The following is a good understanding by comparing the common promise writing method:

async function asyncFunc() {
const result = await otherAsyncFunc();// otherAsyncFunc() returns a Promise object
console.log(result);
}
// Equivalent to:
function asyncFunc() {
return otherAsyncFunc()// otherAsyncFunc() returns a Promise object
.then(result => {
console.log(result);
});
}

The advantage is more obvious when processing multiple asynchronous functions in sequence:

async function asyncFunc() {
const result1 = await otherAsyncFunc1();// otherAsyncFunc1() returns a Promise object
console.log(result1);
const result2 = await otherAsyncFunc2();// otherAsyncFunc2() returns a Promise object
console.log(result2);
}
// Equivalent to:
function asyncFunc() {
return otherAsyncFunc1()// otherAsyncFunc1() returns a Promise object
.then(result1 => {
console.log(result1);
return otherAsyncFunc2();// otherAsyncFunc2() returns a Promise object
})
.then(result2 => {
console.log(result2);
});
}

Process multiple asynchronous functions in parallel:

async function asyncFunc() {
const [result1, result2] = await Promise.all([
otherAsyncFunc1(),// otherAsyncFunc1() returns a Promise object
otherAsyncFunc2() // otherAsyncFunc2() returns a Promise object
]);
console.log(result1, result2);
}
// Equivalent to:
function asyncFunc() {
return Promise.all([
otherAsyncFunc1(),// otherAsyncFunc1() returns a Promise object
otherAsyncFunc2() // otherAsyncFunc2() returns a Promise object
])
.then([result1, result2] => {
console.log(result1, result2);
});
}

Handling errors:

async function asyncFunc() {
try {
await otherAsyncFunc();// otherAsyncFunc() returns a Promise object
} catch (err) {
console.error(err);
}
}
// Equivalent to:
function asyncFunc() {
return otherAsyncFunc()// otherAsyncFunc() returns a Promise object
.catch(err => {
console.error(err);
});
}

ES 9 new features After the introduction of asynchronous iterators, they are just like regular iterators, except that the next() method returns a Promise. Therefore, await can be used with for...of loops to run asynchronous operations in a serial manner.

async function func(array) {
  for await (let i of array) {// Asynchronous iteration
    someFunc(i);
  }
}

A Promise call chain either successfully reaches the last .then(), or fails to trigger .catch(). In some cases, you want to run the same code regardless of the success or failure of the Promise, such as clearing the array, deleting the dialog, closing the database connection, etc. .finally() allows for this purpose.

function func() {
  promiseFunc() // Return a Promise object
    .then(() => {})
    .then(() => {})
    .catch(err => {
      console.log(err);
    })
    .finally(() => {
     // Regardless of whether promiseFunc() runs successfully or fails, the code here will be called
});
    });
}

Revised the literal escape Before ES9, \u means Unicode escape, \x means hexadecimal escape, \ followed by a number means octal escape, which makes it impossible to create a specific string, such as Windows file path C:\uuu\ xxx\111. To remove the syntax restriction of escape sequences, you can use the markup function String.raw before the template string.

let s = `\u{54}` //will be escaped into unicode "T"
console.log(s);//>> T
let str = String.raw`\u{54}`; // will not be escaped
console.log(str);//>> \u{54}

Rest / Spread This is what we usually call the three points... This feature has been introduced in ES6, but the role of objects in ES6 is limited to arrays. In ES9, rest parameters and spread operators like arrays are provided for objects:

const obj = {
a: 1,
b: 2,
c: 3
};
const {a, ...param} = obj; //here... is rest
console.log(a); //>> 1
console.log(param); //>> {b: 2, c: 3}
function foo({ a, ...param }) {//here... still rest
console.log(a); //>> 1
console.log(param); //>> {b: 2, c: 3}
}
const param = {b: 2, c: 3 };
foo({ a: 1, ...param }); //here...is spread

Regular expression dotAll mode The midpoint of the regular expression. Matches any single character except carriage return. The mark s changes this behavior, allowing carriage return and line feed to be matched.

/hello.world/.test('hello\nworld');  // false
/hello.world/s.test('hello\nworld'); // true
console.log(/hello.world/s.test(`hello
world`))   //>> true

Regular expression named capture group After using exec() to match in Javascript regular expressions, it can return an array-like object containing the matched string.

const reDate = /(\d{4})-(\d{2})-(\d{2})/,
match = reDate.exec("2018-08-06");
console.log(match);//>> [2018-08-06, 2018, 08, 06]
//In this way, you can directly use the index to get the year, month, and day:
let year = match[1]; //>> 2018
let month = match[2]; //>> 08
let day = match[3]; //>> 06

The 0th item of the returned array is the text that matches the regular expression, the first item is the text that matches the first group \d{4} of reDate (if any), and the second item is the text that matches the reDate The text matched by the second group \d{2} (if any), and so on. Groups of regular expressions are wrapped in (). In the above case, if the date format is changed to month, day and year, then after changing the structure of the regular expression, it may also change the code of the variable assignment part. The following example:

const reDate = /(\d{2})-(\d{2})-(\d{4})/,//The expression structure has changed
match = reDate.exec("08-06-2018");
console.log(match);//>> [08-06-2018, 08, 06, 2018]
//At this time, the assignment code of year, month, and day has to be changed too, there are so many changes! How to do?
let year = match[3]; //>> 2018
let month = match[1]; //>> 08
let day = match[2]; //>> 06

It can be found that there are too many changes in the above wording. Is there any way to change the code less and save trouble? Have! ES9 allows the use of the symbol ? to name the capture group (that is, the "matched group"), an example is as follows:

const reDate = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
match = reDate.exec("2018-08-06");
console.log(match);
//>> [2018-08-06, 08, 06, 2018, groups: {day: 06, month: 08, year: 2018}]
//At this time, use the groups object to get the year, month and day, no matter how the regular expression is changed, the following three lines do not need to be changed, which saves trouble!
let year = match.groups.year; //>> 2018
let month = match.groups.month; //>> 08
let day = match.groups.day; //>> 06

Regular expression Unicode escape Before ES9, local access to Unicode character attributes in regular expressions was not allowed. ES9 adds Unicode attribute escapes in the form of \p{...} and \P{...}, using the mark u (unicode) setting in the regular expression, in the {...} of \p, You can use key-value pairs to set the attributes that need to be matched instead of specific content.

const regex = /\p{Script=Greek}/u;//Greek means Greek
console.log(regex.test('a')); //>> flase
console.log(regex.test('Σ')); //>> true