What’s New in ES2021?
Stay updated with the upcoming features to JavaScript in 2021
Since 2015, JavaScript has been receiving constant yearly updates with new features being added. Though ES2021/ES12 will be released next year, we can already have a look at what’s to come since many features already reached Stage 4(Finished) specification and will be included in the specification. In this article, I will discuss the features that have already reached stage four and are added to the Google Chrome V8 engine.
String.prototype.replaceAll
String.prototype.replace
is an existing method that allows us to replace a pattern in a string with something else. One thing to remember in this method is that, when we replace a pattern, only the first occurrence of that pattern in the string would be replaced. To replace all the occurrences, we use RegEx to achieve the same.
const str = 'I love Javascript and Javascript is awesome!';
str.replace('Javascript', 'coding');
// "I love coding and Javascript is awesome!"// Alternate solution to replace all occurrences
str.replace(/Javascript/g, 'coding');
// "I love coding and coding is awesome!"
All these years there was no method like replaceAll, to replace all the occurrences without using RegEx. In ES2021, this new method is introduced to overcome this hurdle.
const str = 'I love Javascript and Javascript is awesome!';
str.replaceAll('Javascript', 'coding');
// "I love coding and coding is awesome!"
Promise.any
Promise.any() method takes in a list of promises and returns a value, as soon as it hits the first resolved promise from the list. If all the promises are rejected then it will throw an AggregatedError
message.
Promise.any(promises).then(
(first) => {
// Any of the promises was fulfilled.
},
(error) => {
// All of the promises were rejected.
}
);
This method is different from Promise.race
because with race
, the promise short-circuits once when one of the given promises resolves or rejects, but here it resolves if any of the promises are fulfilled and it is rejected only if all the promises are rejected.
Here’s an example demonstrating the same:
Promise.any([new Promise((resolve, reject) => setTimeout(reject, 200, 'One')),new Promise((resolve, reject) => setTimeout(resolve, 1000, 'Two')),new Promise((resolve, reject) => setTimeout(resolve, 2000, 'Three'))]).then((value) => console.log(`Result - ${value}`)).catch((err) => console.log(err));
// OUTPUT
// Result - Two
Logical Assignment Operators
Logical assignment operator combines the logical operations(&&
, ||
or ??
) with assignment operator.
1. Logical Assignment Operator with && operator
a &&= b
will return b
if both a
and b
are truthy, or it’ll return a
. In other words, it assign RHS variable value to LHS variable, only if LHS value is truthy.
Example:
let a = 1;
let b = 2;a &&= b// Ora && (a = b)// Or if(a) {
a = b
}// OUTPUT
// 2
2. Logical Assignment Operator with || operator
a ||= b
will return a
if a
is truthy, or it’ll return b
. In other words, it assign RHS variable value to LHS variable, only if LHS value is falsy.
Example:
let a;
let b = 2;a ||= b// Ora || (a = b)// Orif(!a) {
a = b
}// OUTPUT
// 2
3. Logical Assignment Operator with ?? operator
??
is also known as the Nullish Coalescing operator, which checks if the value is null
or undefined
. a ??= b
will return b
if a
is null
or undefined
, or it’ll return b
. In other words, it assign RHS variable value to LHS variable, only if LHS value is null
or undefined
.
Example:
let a;
let b = 2;a ??= b// Ora ?? (a = b)// Orif(!a) {
a = b
}// OUTPUT
// 2
Numeric Separators
Numeric Separators will make it easier to read numeric values by using the _
character to provide a separation between groups of digits.
rs = 1_00_000;
// 100000
This is used just as a representation, as it’ll be easier for developers to read through the code.
WeakRefs
WeakRef
stands for Weak References. The main use of weak references is to implement caches.
Since JavaScript is a garbage collected language, if a variable is no longer reachable, the GC automatically removes it. As a good practice, we would not want to keep a lot in memory for a long time. We can allow the memory to be garbage collected and later if we need it again, we can generate a fresh cache.
Example:
// callback function
const callback = () => {
const obj = {
name: "Harsha"
};
console.log(obj);
}// IIFE function to print the object after 3 secs
(async function(){
await new Promise((resolve) => {
setTimeout(() => {
callback(); // {name: "Harsha"}
resolve();
}, 3000);
});
})();
The above example might seem complicated. But, it is actually simple. The code basically calls a callback function after 3 seconds, where the function prints an object. Whenever we call the callback function, the obj
is still present in the memory. To manage cache efficiently we can use WeakRef
.
// callback function
const callback = () => {
const obj = new WeakRef({
name: "Harsha"
});
console.log(obj.deref().name);
}// IIFE function to print the object after 2 and 5 secs
(async function(){
await new Promise((resolve) => {
setTimeout(() => {
callback(); // Guaranteed to print "Harsha"
resolve();
}, 2000);
});
await new Promise((resolve) => {
setTimeout(() => {
callback(); // No Gaurantee that "Harsha" is printed
resolve();
}, 5000);
});
})();
Here in WeakRef
the reference is read using deref()
method. The value will be printed the first time, and for the second time there is no guarantee that it’ll be printed, as it might have been cleaned by the GC.
FinalizationRegistry
FinalizationRegistry
lets programmers register callbacks to be invoked after an object is garbage collected. It is said to be a companion feature of WeakRef
.
const registry = new FinalizationRegistry((value) => {
console.log(value);
});
Here registry
is an instance of FinalizationRegistry
. The callback function passed to FinalizationRegistry
gets triggered when an object is garbage collected.
Example:
(function () {
const obj = {};
registry.register(obj, "Harsha");
})();
When obj
is garbage collected, "Harsha"
is passed to the callback function and is printed in the console.

Intl.ListFormat
The Intl.ListFormat
object is a constructor for objects that enable language-sensitive list formatting. It takes in two parameters — the first parameter is locale and second parameter is an options object that has two properties — style and type. Having a look at an example will be easier than explaining in words:
const list = ['King', 'Queen', 'Jack'];
new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }).format(list);
// King, Queen and Jack
new Intl.ListFormat('en', { style: 'short', type: 'disjunction' }).format(list);
// King, Queen or Jack
You can also try other languages.
dateStyle and timeStyle options for Intl.DateTimeFormat
Now, we can use dateStyle
and timeStyle
to request a locale-specific date and time of a given length. We just need to pass them as options and the rest is handled.
// short
new Intl.DateTimeFormat("en" , {
timeStyle: "short"
}).format(Date.now())
// "6:35 PM"
// medium
new Intl.DateTimeFormat("en" , {
timeStyle: "medium"
}).format(Date.now())
// "6:35:13 PM"
// long
new Intl.DateTimeFormat("en" , {
timeStyle: "long"
}).format(Date.now())
// "6:35:55 PM GMT+5:30"
And for dateStyle
here are a few examples:
// short
new Intl.DateTimeFormat("en" , {
dateStyle: "short"
}).format(Date.now())
// "11/19/20"
// medium
new Intl.DateTimeFormat("en" , {
dateStyle: "medium"
}).format(Date.now())
// "Nov 19, 2020"
// long
new Intl.DateTimeFormat("en" , {
dateStyle: "long"
}).format(Date.now())
// "November 19, 2020"
Conclusion
As a developer, it is important to stay up-to-date with the new features of any programming language. I hope, I have given you a brief idea of what are all yet to come.
Thank you for reading and drop your favourite feature in the comments!