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:
- Add after the integer literal
n
.
let bigIntNum1=9007199254740999n;
console.log(typeof bigIntNum1)//bigint
Copy the code
- use
BigInt
Function.
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:
BigInt
It’s a new type of primitive. Note the standard numbers andBigInt
Numbers should not be mixed.
typeof 9007199254740993n; // -> 'bigint'
Copy the code
- Avoid calling functions whenever possible
BigInt
Method to instantiate a large integer. Because the parameter literals actually are tooNumber
An 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({ code: 200.msg:"Request successful"})
})
let b= new Promise((resolve,reject) = >{
// Async operation...
resolve({ code: 200.msg:"Request successful"})
})
let c= new Promise((resolve,reject) = >{
// Async operation...
reject({ code: 500.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({ code: 200.msg:"Request successful"})
})
let b= new Promise((resolve,reject) = >{
// Async operation...
resolve({ code: 200.msg:"Request successful"})
})
let c= new Promise((resolve,reject) = >{
// Async operation...
reject({ code: 500.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.