ECMAScript 2020 is the 11th edition of the ECMAScript language specification. Since its first edition in 1997, ECMAScript has grown into one of the most widely used general-purpose programming languages in the world.

ES2020(ES11) introduces the following new features:

  • The matchAll method of String
  • Dynamic import statement import()
  • import.meta
  • export * as ns from ‘module’
  • Promise.allSettled
  • A new data type: BigInt
  • GlobalThis
  • Promise.allSettled
  • A new data type: BigInt
  • Nullish coalescing Operator

matchAll

The matchAll() method returns an iterator containing all the results of the matched regular expression. Use for… Of traversal or using the operator… Array.from converts it to an Array.

const reg =  /[0-3]/g;
const data = '2020';
console.log(data.matchAll(reg)); // The return value of data.matchAll is an iterator
console.log([...data.matchAll(reg)]);
Copy the code

/ *

  • 0: [“2”, index: 0, input: “2020”, groups: undefined]
  • 1: [“0”, index: 1, input: “2020”, groups: undefined]
  • 2: [“2”, index: 2, input: “2020”, groups: undefined]
  • 3: [“0”, index: 3, input: “2020”, groups: undefined]

* /

Dynamic import

The standard import method is static, so all imported modules will be translated at load time (no on-demand compilation, slowing down the front page loading). In some scenarios where you may want to import modules conditionally or on demand, you can use dynamic imports instead of static imports.

Before import(), we had to use require() when we needed to import modules conditionally.

Such as:

if(XXX){
	const menu = require('./menu');
}
Copy the code

Today it can be replaced by:

if(XXX){
	const menu = import('./menu');
}
Copy the code

@babel/preset-env already contains @babel/ plugin-syntact-dynamic-import, so to use the import() syntax, you just need to configure @babel/preset-env.

Tip: Do not abuse dynamic imports (only if necessary). Static frameworks are better at initializing dependencies and are more useful for static analysis tools and Tree Shaking.

In addition, import() returns a Promise object, such as:

//menu.js
export default {
    menu: 'menu'
}
//index.js
if(true) {
    let menu = import('./menu');
    console.log(menu); //Promise {<pending>
    menu.then(data= > console.log(data));//Module {default: {menu: "menu"}, __esModule: true, Symbol(Symbol.toStringTag): "Module"}
} else{}Copy the code

import.meta

Import. meta returns an object with a URL attribute that returns the url path of the current module and can only be used within the module.

<script src='./main.js' type="module"></script>
//main.js
console.log(import.meta); / / {url: "http://localhost:8080/main.js"} PS: USES HTTP -s < script SRC = ". / main. Js' type = "module" > < / script >
//main.js
console.log(import.meta); / / {url: "http://localhost:8080/main.js"} PS: using the HTTP server startup
Copy the code

Because the import. Meta must be used inside the module, if not add type = “module”, the console complains: always use a ‘import. Meta’ outside a module.

The @babel/preset-env and @babel/preset- React presets are configured. The following error is reported when using import.meta:

Install @open-wc/webpack-import-meta-loader, modify webPack configuration, and it works properly.

module: {
    rules: [
        {
            test: /\.js$/,
            use: [
                require.resolve('@open-wc/webpack-import-meta-loader'),
                {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            "@babel/preset-env",
                            "@babel/preset-react"
                        ]
                    },
                }
            ]
        }
    ]
}
Copy the code

The effect is as follows:

//src/index.js
import React from 'react';
console.log(import.meta);/ / {index. Js: 38 {url: "http://127.0.0.1:3000/src/index.js"}}
Copy the code

export * as ns from ‘module’

ES2020 added export * as XX from ‘module’, and import * as XX from ‘module’

//menu.js
export * as ns from './info';
Copy the code

The following two statements are combined into one sentence:

import * as ns from './info';
export { ns };
Copy the code

Note that export * as ns from ‘./info’ does not actually import the module, so we will not get ns in the module (menu.js).

Promise.allSettled

Promise.all or promise. race sometimes doesn’t meet our needs. For example, we need to do something when all the promises are finished, regardless of whether they succeed or fail. Before we have no promise. allSettled, we need to write our own fulfillment.

The promise.allsettled () method returns a Promise after all the given promises have been fulfilled or rejected, with an array of objects, each representing the corresponding Promise result.

const promise1 = Promise.resolve(100);
const promise2 = new Promise((resolve, reject) = > setTimeout(reject, 100.'info'));
const promise3 = new Promise((resolve, reject) = > setTimeout(resolve, 200.'name'))

Promise.allSettled([promise1, promise2, promise3]).
    then((results) = > console.log(result));
/* [ { status: 'fulfilled', value: 100 }, { status: 'rejected', reason: 'info' }, { status: 'fulfilled', value: 'name' } ]Copy the code

As you can see, the successful result of promise.allsettled () is an array where each item is an object with a status attribute of either fulfilled or rejected. If status is fulfilled, The object also has a value property, whose value is the result of the corresponding promise’s success; If the value of status is rejectedd, then the object has a reason attribute whose value is the reason why the corresponding promise failed.

BigInt

BigInt is a numeric type of data that can represent an integer in any precision format. Before this, the maximum Number safe in JS is 9009199254740091, that is, 2^53-1, which can be viewed by entering number. MAX_SAFE_INTEGER in the console. Beyond this value, JS has no way to accurately represent. In addition, any value greater than or equal to 2 ^ 1024, which JS cannot represent, will return Infinity.

BigInt solves both of these problems. BigInt is only used to represent integers. There is no limit to the number of bits. An integer of any number of bits can be accurately represented. In order to distinguish BigInt from Number, data of type BigInt must be suffix n.

// The Number type exceeds 9009199254740991
const num1 = 90091992547409910;
console.log(num1 + 1); / / 90091992547409900

//BigInt = BigInt
const num2 = 90091992547409910n;
console.log(num2 + 1n); //90091992547409911n
// The Number type cannot represent a value greater than 2 to the power of 1024
let num3 = 9999;
for(let i = 0; i < 10; i++) {
    num3 = num3 * num3;
}
console.log(num3); //Infinity

//BigInt can represent an integer with any number of bits
let num4 = 9999n;
for(let i = 0n; i < 10n; i++) {
    num4 = num4 * num4;
}
console.log(num4); // A string of super long numbers is not posted here
Copy the code

We can also initialize a BigInt instance with a BigInt object:

console.log(BigInt(999)); // 999n note: no new keyword!!
Copy the code

Note that BigInt and Number are two types of data and cannot be used to perform four operations directly, but can be used to compare.

console.log(99n= =99); //true
console.log(99n= = =99); //false 
console.log(99n + 1);//TypeError: Cannot mix BigInt and other types, use explicit conversionss
Copy the code

GlobalThis

There is a top-level object in JS, but the top-level object is not uniform across implementations.

Different statements are required to obtain global objects from different Javascript environments. In the Web, global objects can be obtained through window and self, but in Web Workers, only self can. In Node.js, neither of these is available and global must be used.

Before globalThis, we get the global object like this:

var getGlobal = function () {
    if (typeofself ! = ='undefined') { return self; }
    if (typeof window! = ='undefined') { return window; }
    if (typeof global! = ='undefined') { return global; }
    throw new Error('unable to locate global object');
};
Copy the code

ES2020 introduces globalThis as a top-level object. In any environment, it is easy to get the top-level object through globalThis.

Nullish coalescing Operator

ES2020 has added an operator?? . Returns the right operand if the side operation is null or undefined, otherwise returns the left operand.

Use | | operators, when the left operand is 0, null, and undefined, NaN, false, “‘, are used on the right side of the operator, if use | | to set default values for certain variables, may encounter unexpected behavior.

Such as:

const defaultValue = 100;
let value = someValue || defaultValue;
// When someValue is converted from Boolean to false, the value of value is defaultValue
Copy the code

When someValue is 0, we expect value to be 0, but it is incorrectly assigned to 100.

?? The operator can get around this problem by returning the right-hand operand only if the left-hand operand is null or undefined.

const defaultValue = 100;
let value = someValue || defaultValue;//someValue is 0 and value is 0
Copy the code

Optional Chaining

Optional chain operator? Allows the value of properties that are read deep in the chain of connected objects without having to explicitly verify that each reference in the chain is valid. ? The. Operator functions like the.chain operator, except that it does not cause an error if the reference is nullish, and the expression short-circuited to the return value is undefined.

For example, we want to visit tortoise of the Info object’s Animal reptile. But we don’t know if Animal Reptile exists, so we need to write this:

const tortoise = info.animal && info.animal.reptile && info.animal.reptile.tortoise;
Copy the code

Because null.reptile or undefined.. Reptile will throw an error: TypeError: Cannot read property ‘reptile’ of undefined or TypeError: Cannot read property ‘reptile’ of null, in order to avoid errors, this code will get longer and longer if we need to access deeper properties.

And with the optional chain operator, right? We no longer need to check info.animal before accessing the reptile. Also, on a visit to the info. Animal. Reptile. Tortoise before, also do not need to check the info. The animal. The value of reptile.

The above code is simplified as:

consttortoise = info.animal? .reptile? .tortoise;Copy the code

JS implicitly checks to make sure info.animal is not null or undefined before attempting to access info.animal. Reptile. If it is null or undefined, Then the expression short-circuit calculation returns undefined directly.

Can you see the optional chain operator? The void merge operator is used for both null and undefined values.

So far, the new features of ES2020 are all introduced, generally speaking, the new content is not much, a cup of coffee can be mastered, but still need to review often, otherwise it will be easy to forget.