What is new in ES2021 or ES12
Foreword
On March 13, 2021, the ES2021 candidate proposal released a version of its final feature set. If it can be passed at the ECMA conference in June this year, it will become an official standard!
The new ECMAScript features mentioned in this candidate proposal are as follows:
- String.prototype.replaceAll()
- Promise.any
- Logical operators and assignment expressions
- Numeric separator
- WeakRef and Finalizers
These new features have entered the fourth phase and have been added to the Google Chrome V8 engine. Next, let's introduce these new features of ES2021.
String.prototype.replaceAll()
const newString = oldString.replaceAll(pattern, replacement);
This method returns a new string with all pattern
the substitutions passed to it replacement
where the pattern
argument can be a string or a regular expression, and the replacement
argument can be a string or a function to execute for each match.
replaceAll
The method is the sequel to the String.replace method, String.replace only replaces patternthe first found position.
const str = "Linda is a self-taught developer.Linda will rule the world";
let newStr = str.replace("Linda","Micheal")
//output: Micheal is a self-taught developer.Linda will rule the world
let newStr = str.replaceAll("Linda","Micheal")
//output: Micheal is a self-taught developer.Micheal will rule the world
In the past, if you needed to replace all matching items, you had to write a regular expression to perform a complete replacement.
const str = "hello world, hello code";
const newStr = str.replace(/hello/g, "hi");
console.log(newStr); // "hi world, hi code"
There is now String.prototype.replaceAll()complete replacement of matches even in the input string.
const str = "hello world, hello code";
const newStr = str.replaceAll("hello", "hi");
console.log(newStr); // "hi world, hi code"
Promise.any
The Promise.race()
and Promise.all()
added in ES2020 Promise.allSettled()
. ES2021 added another method to make Promise
processing easier:Promise.any()
Promise.any()
Takes an Promise
iterable, and as long as one of them promise
succeeds, return the one that has succeeded promise
(as in Example 1). If none of the iterables promise
succeed (i.e. all promise
fail/reject), return an instance of the failed promise
sum AggregateErrortype
(as shown in example 2), which is Error
a subclass of , which is used to group a single error in Together.
Promise.any()
It is very similar Promise.race()to a method, except that it does not end because a certain state Promisebecomes rejected.
// example 1
Promise.any([
new Promise((resolve, reject) => setTimeout(reject, 200, 'Third')),
new Promise((resolve, reject) => setTimeout(resolve, 1000, 'Second')),
new Promise((resolve, reject) => setTimeout(resolve, 2000, 'First')),
])
.then(value => console.log(`Result1: ${value}`))
.catch(err => console.log(err))
Promise.race([
new Promise((resolve, reject) => setTimeout(reject, 200, 'Third')),
new Promise((resolve, reject) => setTimeout(resolve, 1000, 'Second')),
new Promise((resolve, reject) => setTimeout(resolve, 2000, 'First')),
])
.then(value => console.log(`Result2: ${value}`))
.catch(err => console.log(err))
/****Output****/
// Third
// Result1: Second
In the above code, Promise.any()
the parameter array of the method contains three Promise operations. As long as one of them becomes fulfilled
, Promise.any()
the returned Promise object becomes fulfilled
, and Promise.race([p1, p2, p3])
whichever result gets faster, returns that result, regardless of whether the result itself is a success state or a failure state.
Promise.any()
Returns AggregateError
an error if no promise is fulfilled .
// example 2
const pErr1 = new Promise((resolve, reject) => {
reject('always fail 1');
});
const pErr2 = new Promise((resolve, reject) => {
reject('Always fail 2');
});
Promise.any([pErr1,pErr2]).catch((err) => {
console.log(err);
})
/****Output****/
// "AggregateError: All promises were rejected"
Logical operators and assignment expressions (&&=, ||=, ??=)
There are many assignment and logical operators in JavaScript, such as the following basic example:
// Assignment Operator Example
let num = 5
num+=10
console.log(num) // 15
// Logical Operator Example
let num1 = 6
let num2 = 3
console.log(num1 === 6 && num2 === 2) // false
console.log(num1 === 6 || num2 === 2) // true
The new proposal will allow us to combine logical operators with assignment operators
1. Logical assignment operator with && operator
var x = 1;
var y = 2;
x &&= y;
console.log(x); // 2
The operation on line 3 is equivalent to: x && (x = y)
or equivalent to
if(x) {
x = y
}
Since x is the real value, the value y is assigned, which is 2. In short, the operator &&=assigns the value of the RHS variable to the LHS variable only if the LHS value is true.
2. Operators with || Logical assignment operator
The RHS variable value is assigned to the LHS variable only if the LHS value is false.
// Logical Assignment Operator with || operator
let num1
let num2 = 10
num1 ||= num2
console.log(num1) // 10
// Line 4 can also be written as following ways
// 1. num1 || (num1 = num2)
// 2. if (!num1) num1 = num2
3. Logical assignment operator with ?? operator
ES2020 introduced the null coalescing operator, which can also be combined with the assignment operator. The RHS variable value is assigned to the LHS variable only if LHS is undefined or simply null.
// Logical Assignment Operator with ?? operator
let num1
let num2 = 10
num1 ??= num2
console.log(num1) // 10
num1 = false
num1 ??= num2
console.log(num1) // false
// Line 4 can also be written as following ways
// num1 ?? (num1 = num2)
Numeric separator
We will make reading numerical values easier and improve readability by using the _ (underscore) character to provide separation between groups of numbers .
let x = 100_000; // 100000
Numeric separators also work for BigInt numbers.
const trillion = 1000_000_000_000n;
console.log(trillion.toString()); // "1000000000000"
Delimiters are for readability purposes only. Therefore, it can be placed anywhere in the number.
const amount = 178_00;
console.log(amount.toString()); // "17800"
WeakRef and Finalizers
This feature consists of two advanced objects WeakRef
and FinalizationRegistry
. Depending on the use case, these interfaces can be used individually or together. **The official recommendation is not to use WeakRef
and finalizer
. **One reason is that they can be unpredictable, another is that they don't really do the job for the gc and may actually make garbage collection's job harder.
In JavaScript, when you create a reference that creates an object, this reference prevents the object from being garbage collected, which means JavaScript cannot delete the object and free its memory. This object can be made to exist forever as long as the reference to the object persists.
ES2021 has new classes WeakRefs
. Allows creation of weak references to objects. This allows existing objects to be tracked without preventing them from being garbage collected. Very useful for caching and object mapping.
New ones must be created with the new
keyword WeakRef
and put some object in parentheses as parameters. When you want to read a reference (the referenced object), you can do so by calling deref()
on.
const myWeakRef = new WeakRef({
name: 'Hoshino',
year: '25'
})
myWeakRef.deref()
// => { name: 'Hoshino', year: '25' }
myWeakRef.deref().name
// => 'Hoshino'
WeakRef
Closely linked to is another function called finalizersor FinalizationRegistry
. This feature allows you to register a callback function that will be called when the object is garbage collected.
// Create FinalizationRegistry:
const reg = new FinalizationRegistry((val) => {
console.log(val)
})
(() => {
// Create new object:
const obj = {}
//Register finalizer for "obj" object:
//First parameter: the object to register the finalizer for.
//The second parameter: the value of the callback function defined above.
reg.register(obj, 'obj has been garbage-collected.')
})()
// output when "obj" is garbage collected:
// 'obj has been garbage-collected.'