preface

ES2020 (ES11) is the version of ECMAScript for the year 2020. 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. That way, you can quickly understand these new features without the need for complicated explanations. Well, without further ado, let’s get to the main body 🔛

Private variables

One of the main functions of a class is to enclose our code in reusable modules. So it will be used in many different places in the same class, but some of the properties in a class, for safety or other purpose, don’t want other classes to be able to visit him, change him, only his own use, for some learned c #, Java language, such as students is better understood, is an access modifier Private, So what do we do in our JS,

Don’t worry, they have what js has, and ES11 provides us with private variables, too. By adding a hash symbol # to the front of a variable or function, you can make them private and only available inside a class.

This is our normal class

class Money{

  constructor(money){

    this.money=money;

  }

}

let RMB=new Money(999);

RMB.money=999999;// This is not bad, how can you change the amount

console.log(RMB.money);// Can be accessed as an object

Copy the code

For security reasons, we can’t let other classes change the values of properties in our class. We can use private properties, which can only be accessed within the class

class Money{

      #money=0;Declare this property to be private

      constructor(money){

        this.#money=money;

      }

    }

    let RMB=new Money(999);

    //RMB.#money=999999; //Uncaught SyntaxError: Private field '#money' must be declared in an enclosing class,

    console.log(RMB.#money);//Uncaught SyntaxError: Private field '#money' must be declared in an enclosing class

Copy the code

The above code reported an error, cryCan not get the value of the private attribute, what to do?

I need to use the money in my class. How do I get it

We can write two methods inside the class, fetch data, write data, you can change it, but you can’t change it arbitrarily, you have to change it through my method, and we can look at the code below

class Money{

  #money=0;Declare this property to be private

  constructor(money){

    this.#money=money;

  }

  getMoney(){/ / get the value

    return this.#money;

  }

  setMoney(money){/ / write values

    this.#money+=money;

  }

}

let RMB=new Money(999);

RMB.setMoney(8848)

console.log(RMB.getMoney());

Copy the code

Ok, so much for private variables (attributes), let’s take a look at null-value merge operators!

Null-value merge operator

In our normal work, when we take a property in an object, if the property has no value, we give it a default value like this

let user={

  name:'Symbol..

  age:18

}

console.log(user.name,"name")/ / Symbol name

console.log(user.like,"like")//undefined "like"

// The object has a default value when it does not have this property

console.log(user.like || 'Write code'."like2")// write code like2



Copy the code
/ / ES2020?? Null-value merge operator

console.log(user.sex??'male'."sex");  / / the male sex

  // If the sex attribute does not exist, the default value will be used

Copy the code

** null value merge operator (??) ** is a logical operator. When the left-hand operand is null or undefined, it returns the right-hand operand. Otherwise return the left-hand operand.

?? And | | what is the difference??

The biggest difference between them is “and 0,?? If the value to the left of is “or 0, the value to the left is still returned;

| | to the left to a Boolean data type conversion, so ‘and 0 will be converted to false, return to the right of the value

Optional chain operator

Reduce the problem of determining whether attributes exist when accessing deep objects.

const a = {};



console.log(a.b.c); // Err is reported, c cannot be obtained from undefined



console.log(person? .profile? .name);/ / ""

console.log(person? .hobby? .work);// undefined



console.log(person? .hobby? .work ??"no Work"); // no Work

Copy the code

Optional chain? Indicates that if the expression to the left of the question mark has a value, the field following the question mark continues to be queried. As can be seen from the above, using the optional chain can greatly simplify the similar tedious pre-check operation, and it is safer.

Note:? Cannot be used for assignment.

For assignment, we usually combine the optional chain operator with the null-value merge operator

let user={

  name:'Symbol..

  age:18.

  skill: {

    Web: {

      html:'50%'.

      css:'60%'.

      js:'80%'

    },

    Server: {

      node:'80%'.

      php:'50%'.

      net:'60%'

    }

  }

}

console.log(user.name,"name")/ / Symbol name

console.log(user.like,"like")//undefined "like"

// We use this as a default value for objects that do not have this property

console.log(user.like || 'Write code'."like2")// write code like2



//ES2020 的??



console.log(user.sex??'male'."sex");  // If the sex attribute does not exist, the default value will be used



console.log(user.skill.Web.js,"js")//80% js

//console.log(user.skill.Database.MySql,"MySql")//Uncaught TypeError: Cannot read property 'MySql' of undefined

// The null-value merge operator, combined with optional chains, makes it easy to handle multi-level queries and assign defaults

console.log(user? .skill? .Database? .MySql ??'88%'."MySql")

Copy the code

BigInt

Js float on a precision problem, the most typical is 0.1+0.2! = 0.3

console.log(0.1+0.2.'0.1 + 0.2')/ / 0.30000000000000004 "0.1 + 0.2"

console.log(0.1+0.2= =0.3."0.1 + 0.2 = = 0.3")/ / false "0.1 + 0.2 = = 0.3"

Copy the code

The maximum number that JavaScript can handle is 2 ^ 53, which can be checked by MAX_SAFE_INTEGER:

MIN_SAFE_INTEGER to number. MAX_SAFE_INTEGER. Integer calculations or representations outside this range lose precision.

let maxNum=Number.MAX_SAFE_INTEGER;

console.log(maxNum)/ / 9007199254740991



let num1=Number.MAX_SAFE_INTEGER+1;

let num2=Number.MAX_SAFE_INTEGER+2;

console.log(num1==num2,"num1==num2")//true Beyond this range, precision is lost

Copy the code

To solve this problem, ES2020 provides a new data type: BigInt. There are two ways to use BigInt:

  1. Add after the integer literaln.
let bigIntNum1=9007199254740999n;

console.log(typeof bigIntNum1)//bigint

Copy the code
  1. useBigIntFunction.
let bigIntNum2=BigInt(90071992547409999);

console.log(typeof bigIntNum2)//bigint

Copy the code

Now let’s judge the two-digit number:

console.log(bigIntNum1==bigIntNum2)//false

// The previous problem of not being able to calculate beyond this precision has been solved

Copy the code

With BigInt, we can safely compute large integers.

let BigNum=bigIntNum1+bigIntNum2;

console.log(BigNum.toString())/ / 99079191802150999

Copy the code

Note:

  1. BigIntIt’s a new type of primitive. Note the standard numbers andBigIntNumbers should not be mixed.
typeof 9007199254740993n; // -> 'bigint'

Copy the code
  1. Avoid calling functions whenever possibleBigIntMethod to instantiate a large integer. Because the parameter literals actually are tooNumberAn instantiation of a type, a number outside the safe range, may cause loss of accuracy.

Dynamic import

In a project, some functions might be used infrequently, and importing all dependencies might be a waste of resources. It is now possible to use async/await to dynamically import dependencies when needed. It is possible to load only on demand without loading all logical resources at initialization, which makes the rendering of the first screen faster. Although the Webpack used by our front-end engineering project already supports on-demand import very well, But now that we can officially enter the ES specification in 2020, our JS is getting stronger and stronger.

Demo.js export module:

export const sum=(num1,num2) = >num1+num2;

Copy the code

Dynamic import:

let fun=async(num1,num2)=>{

  let model=await import('./demo.js');

  console.log(model.sum(num1,num2),"Sum of two numbers.")

}

fun(8.9)//17 "Sum of two numbers"



/ / an error

//Access to script at 'file:///C:/Users/Administrator/Desktop/es11Demo/demo.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

   //demo.js:1 Failed to load resource: net::ERR_FAILED

   //demo.html:13 Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: file:///C:/Users/Administrator/Desktop/es11Demo/demo.js



// The error must be reported in the HTTP server environment

Copy the code

Create the HTTP server in the root directory of the current project (the node environment is already on the computer)

NPM I Http-server-g installation dependency

Then execute http-server in the directory

globalThis

JavaScript has different ways to get global objects in different environments, from global in NodeJS to Window, self in The Web, and even this, but this is extremely dangerous, This is extremely complex in JavaScript and relies heavily on the current execution context, which undoubtedly adds to the complexity of retrieving global objects.

  • 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.

  • The global variable global: is valid only in Node.js

We write a JS file, which may run in a browser, may run in a Node environment, may run in a Web Workers environment,

We can use the following method to determine whether to obtain the global object, we can use a global function:

var getGlobal = function ({

  if (typeofself ! = ='undefined') { return self; }

  if(typeofwindow ! = ='undefined') { returnwindow; }

  if (typeofglobal ! = ='undefined') { return global; }

  thrownewError('unable to locate global object');

};

var globals = getGlobal();

Copy the code

Our ES11 provides us with globalThis,

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 provides a standard way to get globalThis objects (that is, global objects themselves) in different environments, so you don’t have to worry about the runtime environment.

// worker.js

console.log(globalThis === self) //true

// node.js

console.log(globalThis === global) //true

/ / the browser

console.log(globalThis === window//true

Copy the code

Promise. All defects

Promise.all is known to have the ability to execute asynchronous tasks concurrently. The biggest problem with this is that if one of the tasks fails, all the tasks hang, and the Promise goes straight into reject.

Picture this: Use Promise. All to consign three interfaces. If any of the interfaces fails, reject will render all of the data in the three regions of the page. Since any reject goes into a catch callback, this is clearly unacceptable, as follows:

let a= new Promise((resolve,reject) = >{

  // Async operation...

  resolve({ code200.msg:"Request successful"})

})

let b= new Promise((resolve,reject) = >{

  // Async operation...

  resolve({ code200.msg:"Request successful"})

})

let c= new Promise((resolve,reject) = >{

  // Async operation...

  reject({ code500.msg:"Server exception"})

})

// Use promise.all to execute asynchronous tasks concurrently

Promise.all([a,b,c])

.then((res) = > {

    // This callback is entered only if all of the above requests are resolved

    console.log(res,"res")

})

.catch((error) = > {

    // Any of the above requests is reject (reject) and this callback is entered

    console.log(error,"error")

    // error: {code: 500, MSG: "service exception "}

})

Copy the code

Promise.allSettled

When we’re dealing with multiple promises, especially if they depend on each other, it can be useful to record the errors that occur during debugging for each event. Using Promise.allSettled, it creates a new Promise and returns an array containing the results of each Promise after all promises are completed.

let a= new Promise((resolve,reject) = >{

  // Async operation...

  resolve({ code200.msg:"Request successful"})

})

let b= new Promise((resolve,reject) = >{

  // Async operation...

  resolve({ code200.msg:"Request successful"})

})

let c= new Promise((resolve,reject) = >{

  // Async operation...

  reject({ code500.msg:"Server exception"})

})

// use to make concurrent requests

Promise.allSettled([a,b,c]).then((data= >{

  console.log(data,"data")

}))



// This is a big pity. The return data is fulfilled with "status", which means that the request is successful; status: "Rejected", which means that the request fails

Copy the code

Promise. AllSettled advantage

Promise.allSettled is similar to promise. all, which is connected to concurrent requests. In the first two cases, promise. allSettled is connected to concurrent requests. All requests of normal also can’t get the data, but in the development of our business, we need to ensure the largest accessibility, our business is in we perform concurrent tasks, no matter the concurrent tasks in any task I is normal or abnormal, we all need to get back to the corresponding state, In ES11, Promise.AllSettled this for us, Similar to promise.all, the parameter takes an array of promises and returns a new Promise, meaning that when all promises have been processed, we can get the state of each Promise, regardless of whether the processing was successful. We can use filters in then to filter out the desired business logic result, which addresses the promise.all flaw.