What new in ES2021 (aka ES12)?
November 05, 2020
Last year, I wrote a blog to summarize the brief history of javascript from ES6
to ES11
. If you didn’t read it yet, you can check out here.
Every year, javascript got the new update. ECMAScript 2021(ES2021) version is expected to be released in the month of June 2021.
List down below is some new updates of ES2021 (aka ES12) that have been proposed in ECMAScript proposal (final stage):
- String replaceAll() Method
- Private Methods
- Private Accessors
- Logical Operators and Assignment Expressions
- WeakRef and Finalizers
- Promise.any() and AggregateError
- Numeric Separators
- Intl.ListFormat
- dateStyle and timeStyle options for Intl.DateTimeFormat
Some of the codes and examples, I got it from:
String replaceAll() Method
With this new update, we are able to replaceAll the string with the new string using string.replaceAll()
method.
Old approach
// in the previous versionlet string = 'The dog is eating dogfood.';let newString = string.replace('dog','cat');console.log(newString);// output: The cat is eating dogfood.
// To replace all the word dog with cat, we need to use regular expression.let string = 'The dog is eating dogfood.';let newString = string.replace(/dog/g,'cat');console.log(newString);// output: The cat is eating catfood.
New approach
// with the new update, we can use method replaceAll()let string = 'The dog is eating dogfood.';let newString = string.replaceAll('dog','cat');console.log(newString);// output: The cat is eating catfood.
Private Methods
Private method is accessible only in its own class. Private method start with #
.
class Car {// Private method#carColor() {console.log("The car is white.");}// Public methodshowCarColor() {this.#carColor();}}const carObj = new Car();carObj.showCarColor(); // "The car is white.";carObj.carColor(); // TypeError: carObj.carColor is not a function
Private Accessors
Private Accessors function start with #
.
class Car {// Public accessorget name() { return 'Honda' }set name(value) {}// Private accessorget #color() { return 'red' }set #color(value) {}}
We can access the Accessors as belows:
const carObj = new Car();console.log(carObj.name); // "Honda"console.log(carObj.color); // undefined
Logical Operators and Assignment Expressions
Logical assignment operator combines the logical operations(&&, || or ??) with assignment.
TL-DR
let a = 1;let b = 2;a ||= b;// equivalent to a = a || bconsole.log(a); // output: 1
let c = 2;let d = 5;c &&= d;// equivalent to c = c && dconsole.log(c); // output: 5
let e;let f = 2;e ??= f;// equivalent to e = e ?? fconsole.log(e) // output: 2
Let’s see the summarize below:
a ||= b
will returna
ifa
isa
truthy value, orb
ifa
is falsyc &&= d
will returnd
if bothc
andd
are truthy, orc
otherwisee ??= f
will returnf
ife
isnull
orundefined
otherwise it will returne
WeakRef and Finalizers
WeakRef
WeakRef
stands for Weak References. Main use of weak references is to implement caches or mappings to large objects.
For example: we don’t want to keep a lot of memory for the rarely used cached or mapping so we can allow memory to be garbage collected and generate the fresh one if we need it.
Read More about javascript garbage collection here.
TL-DR
To create WeakRef we just simply use new WeakRef
and to call the weakref we can use .deref()
.
const callback = () => {const aBigObj = new WeakRef({name: "Backbencher"});console.log(aBigObj.deref().name);}(async function(){await new Promise((resolve) => {setTimeout(() => {callback(); // Guaranteed to print "Backbencher"resolve();}, 2000);});await new Promise((resolve) => {setTimeout(() => {callback(); // No Gaurantee that "Backbencher" is printedresolve();}, 5000);});})();
As you can see the code above the second await cannot Gaurantee the word “Backbencher” is printed which means it is already garbage collected.
Please make sure you use weakref only on the big obj that isn’t so important for your program to run.
Finalizers
FinalizationRegistry
is a companion feature of WeakRef
. It lets programmers register callbacks to be invoked after an object is garbage collected.
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.
(function () {const obj = {};registry.register(obj, "Backbencher");// this will passed the value "Backbencher" to registry when obj is garbage collected.// and will print "Backbencher" as the output.})();
Promise.any() and AggregateError
Promise.any()
resolves if any of the supplied promises is resolved. Below we have 3 promises, which resolves at random times.
const p1 = new Promise((resolve, reject) => {setTimeout(() => resolve("A"), Math.floor(Math.random() * 1000));});const p2 = new Promise((resolve, reject) => {setTimeout(() => resolve("B"), Math.floor(Math.random() * 1000));});const p3 = new Promise((resolve, reject) => {setTimeout(() => resolve("C"), Math.floor(Math.random() * 1000));});
Out of p1
, p2
and p3
, whichever resolves first is taken by Promise.any()
.
(async function() {const result = await Promise.any([p1, p2, p3]);console.log(result); // Prints "A", "B" or "C"})();
What if none of the promises resolve? In that case Promise.any()
throws an AggregateError exception. We need to catch it and handle it.
const p = new Promise((resolve, reject) => reject());try {(async function() {const result = await Promise.any([p]);console.log(result);})();} catch(error) {console.log(error.errors);}
Numeric Separators
The introduction of Numeric Separators will make it easier to read numeric values by using the _ (underscore) character to provide a separation between groups of digits.
Let’s look at more examples:
1_000_000_000 // Ah, so a billion101_475_938.38 // And this is hundreds of millionslet fee = 123_00; // $123 (12300 cents, apparently)let fee = 12_300; // $12,300 (woah, that fee!)let amount = 12345_00; // 12,345 (1234500 cents, apparently)let amount = 123_4500; // 123.45 (4-fixed financial)let amount = 1_234_500; // 1,234,500
Intl.ListFormat
The Intl.ListFormat
object is a constructor for objects that enable language-sensitive list formatting.
The following example shows how to create a formatted list using the English language.
// Create a list formatter in your locale// with default values explicitly passed in.const lf = new Intl.ListFormat("en", {localeMatcher: "best fit", // other values: "lookup"type: "conjunction", // "conjunction", "disjunction" or "unit"style: "long", // other values: "short" or "narrow"});lf.format(['Motorcycle', 'Truck' , 'Car']);// > "Motorcycle, Truck, and Car"
You are not limited to English, let’s try with a few different languages:
const list = ['Apple', 'Orange', 'Banana'];// Italianconsole.log(new Intl.ListFormat('it', { style: 'long', type: 'conjunction' }).format(list));// Apple, Orange e Banana// Spanishconsole.log(new Intl.ListFormat('es', { style: 'long', type: 'conjunction' }).format(list));// Apple, Orange y Banana// Germanconsole.log(new Intl.ListFormat('de', { style: 'long', type: 'conjunction' }).format(list));// Apple, Orange und Banana
dateStyle and timeStyle options for Intl.DateTimeFormat
We can use dateStyle
and timeStyle
to request a locale-specific
date and time of a given length.
// shortnew Intl.DateTimeFormat("en" , {timeStyle: "short"}).format(Date.now())// "2:45 PM"// mediumnew Intl.DateTimeFormat("en" , {timeStyle: "medium"}).format(Date.now())// "2:45:53 PM"// longnew Intl.DateTimeFormat("en" , {timeStyle: "long"}).format(Date.now())// "2:46:05 PM GMT+7"
Now let’s try with dateStyle:
// shortnew Intl.DateTimeFormat("en" , {dateStyle: "short"}).format(Date.now())// "7/25/20"// mediumnew Intl.DateTimeFormat("en" , {dateStyle: "medium"}).format(Date.now())// "Jul 25, 2020"// longnew Intl.DateTimeFormat("en" , {dateStyle: "long"}).format(Date.now())//
🎉🎉That's all for **What's New in Javascript ES2021**! See you next year...🎉🎉