preface

ES2020 is the 2020 version of ECMAScript. This release does not contain as many new features as ES6 (ES2015). But many interesting and useful features have also been added.

This article introduces the new ES2020 features with simple code examples. This way, you can quickly understand these new features without the need for complicated explanations. For more quality articles, please click on the GitHub blog

Optional Chaining operators

Optional chains allow us to query objects with multiple levels without the need for redundant pre-validation.

Uncaught TypeError: Cannot read Property Uncaught TypeError: Cannot read Property Uncaught TypeError: Cannot read Property… This error causes the entire program to abort.

Therefore, you need to modify your code to handle each possible undefined object in the property chain, such as:

let nestedProp = obj && obj.first && obj.first.second;
Copy the code

Before accessing obj.first.second, make sure that the values of obj and obj.first are not null(and not undefined).

With the optional chain call, similar tedious front-check operations can be greatly simplified and more secure:

letnestedProp = obj? .first? .second;Copy the code

If obj or obj.first is null/undefined, the expression will short-circuit the evaluation and return undefined directly.

Optional chain operators are supported:

The Nullish coalescing Operator

When we query an attribute, we often set a default value without the attribute, such as the following two ways:

letc = a ? A: b // Mode 1letC = a | | b / 2 / wayCopy the code

One obvious drawback of both approaches is that they overwrite all false values, such as (0, “, false), which may be valid inputs in certain situations.

let x = {
  profile: {
    name: 'Boat on the waves',
    age: ' '
  }
}
console.log(x.profile.age || 18) //18
Copy the code

In the example above, the age attribute is an empty string, which is equivalent to a false value. To solve this problem, ES2020 has a new feature — the void merge operator, which uses?? Said. If the expression is in?? Returns the default value on the right of the operator evaluated to undefined or null.

letc = a ?? b; / / equivalent to theletc = a ! == undefined && a ! == null ? a : b;Copy the code

For example, there is the following code:

const x = null;
const y = x ?? 500;
console.log(y); // 500
const n = 0
const m = n ?? 9000;
console.log(m) // 0
Copy the code

Void merge operators are supported:

Promise.allSettled

We know promise.all has the ability to execute asynchronous tasks concurrently. The biggest problem is that if any of the promises in the arguments is reject, the whole promise. all call terminates immediately and returns a reject promise object.

const promises = [
 Promise.resolve(1),
 Promise.resolve(2),
 Promise.reject('error')]; Promise.all(promises) .then(responses => console.log(responses)) .catch(e => console.log(e)) //"error"
Copy the code

Imagine a scenario like this: A page has three areas corresponding to three independent interface data. Use promise. all to request three interfaces concurrently. If any interface is abnormal, the state is reject. Promise. AllSettled this pain point:

Promise.allSettled([
  Promise.reject({ code: 500, msg: 'Service exception' }),
  Promise.resolve({ code: 200, list: [] }),
  Promise.resolve({ code: 200, list: [] })
]).then(res => {
  console.log(res)
  /*
        0: {status: "rejected"Reason: {... }} 1: {status:"fulfilled", the value: {... }} 2: {status:"fulfilled", the value: {... }} */ / Filter out the rejected state, RenderContent(res.filter(el => {returnel.status ! = ='rejected'}})))Copy the code

Promise.allsettled is similar to promise.all, in that it accepts an array of promises and returns a new Promise, except that it will not be short-circuited. This means that when all promises are processed, we can get the state of each Promise, regardless of whether they were processed successfully or not.

Promise. AllSettled support:

String.prototype.matchAll

If a regular expression has more than one match in a string, it is now common to use the G or Y modifier to retrieve each match in a loop.

function collectGroup1 (regExp, str) {
  const matches = []
  while (true) {
    const match = regExp.exec(str)
    if (match === null) break
    matches.push(match[1])
  }
  return matches
}
console.log(collectGroup1(/"([^"] *)"/g, `"foo" and "bar" and "baz"`))
// [ 'foo', 'bar', 'baz' ]

Copy the code

It is worth noting that without the modifier /g,.exec() returns only the first match. Now through the String. The prototype. MatchAll method, can one-time remove all matching.

function collectGroup1 (regExp, str) {
  let results = []
  for (const match of str.matchAll(regExp)) {
    results.push(match[1])
  }
  return results
}
console.log(collectGroup1(/"([^"] *)"/g, `"foo" and "bar" and "baz"`)) / / /"foo","bar","baz"]

Copy the code

MatchAll (regex) returns a traverser, so we can use for… Of loop out.

String. The prototype. MatchAll support:

Dynamic import

Nowadays, front-end packaged resources are becoming larger and larger, and front-end application initialization does not need to load all these logical resources. In order to make the first screen render faster, many times dynamic import (load on demand) modules, such as lazy loading of images, can help you improve the performance of the application.

Loading these logical resources on demand is usually done in an event callback:

el.onclick = () => {
  import('/modules/my-module.js') .then(module => { // Do something with the module. }) .catch(err => { // load error; })}Copy the code

Import () can be used in script scripts, and the import(module) function can be called from anywhere. It returns a promise resolved as a module object.

This usage also supports the await keyword.

let module = await import('/modules/my-module.js');
Copy the code

By importing code dynamically, you can reduce the time it takes for your application to load and get something back to the user as quickly as possible.

Dynamic import is supported:

BigInt

One of the reasons javascript has always been so bad at Math is that it can only safely represent -(2^53-1) to the 2^53-1 norm values, i.e., number.min_safe_INTEGER to number.max_safe_INTEGER, Integer calculations or representations outside this range lose precision.

var num = Number.MAX_SAFE_INTEGER; // -> 9007199254740991 num = num + 1; Num = num +1; 9007199254740992 9007199254740992 // Two different values, but returnedtrue
9007199254740992 === 9007199254740993  // -> true
Copy the code

Hence BigInt, the seventh primitive type that can safely evaluate large integers. You can use the same operators on BigInt as normal numbers, such as +, -, /, *, %, etc.

Creating a value of type BigInt is also as simple as adding n after the number. For example, 123 changes to 123N. It can also be converted using the global BigInt(value) method, which takes a value as a number or a numeric string.

const aNumber = 111;
const aBigInt = BigInt(aNumber);
aBigInt === 111n // true
typeof aBigInt === 'bigint' // true
typeof 111 // "number"
typeof 111n // "bigint"
Copy the code

Just add n to the end of the number to calculate large numbers correctly:

1234567890123456789n * 123n;
// -> 151851850485185185047n
Copy the code

One problem, however, is that you cannot mix BigInt with Number in most operations. It is ok to compare Number and BigInt, but not to add them.

1n < 2 
// true

1n + 2
// Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
Copy the code

Support for BigInt:

globalThis

GlobalThis is a new standard method for retrieving globalThis. Previously, developers would get it in the following ways:

  • The global variable window: is a classic method for getting global objects. However, it is not available in Node.js and Web Workers
  • The global variable self: usually only works in Web Workers and browsers. But it does not support Node.js. Some people identify code running in Web Workers and browsers by checking the presence of self
  • The global variable global: is valid only in Node.js

In the past, global objects can be obtained through a global function:

// Prees10 solution const getGlobal =function() {if(typeof self ! = ='undefined') return self
  if(typeof window ! = ='undefined') return window
  if(typeof global ! = ='undefined') return global
  throw new Error('unable to locate global object'Array(0,1,2) // [0,1,2] // define a global object v = {value:true } ,ES10用如下方式定义
globalThis.v = { value:true }
Copy the code

The purpose of globalThis is to provide a standardized way to access global objects. With globalThis, you can access global objects in any context at any time.

GlobalThis will be Window if you are on a browser, and global if you are on Node. As a result, there is no longer a need to consider different environmental issues.

// worker.js
globalThis === self
// node.js
globalThis === global
// browser.js
globalThis === window
Copy the code

The new proposal also states that Object.prototype must be in the global Object’s prototype chain. The following code already returns true in recent browsers:

Object.prototype.isPrototypeOf(globalThis); // true
Copy the code

GlobalThis supports:

Refer to the article

  • TC39 Proposals
  • MDN document
  • Grass ES2020 new features
  • ES2020 Features in simple examples
  • New Features In ES2020 You Should Check
  • 5 ECMAScript Proposals To Look Out For In ES2020