In this tutorial we are going to learn about the new features we can use in the latest version of ECMAScript 2021 with some coding examples
Introduction
This Ecma Standard defines the ECMAScript 2022 Language. It is the twelfth edition of the ECMAScript Language Specification. Since publication of the first edition in 1997, ECMAScript has grown to be one of the world's most widely used general-purpose programming languages. It is best known as the language embedded in web browsers but has also been widely adopted for server and embedded applications.Introduction
This Ecma Standard defines the ECMAScript 2022 Language. It is the twelfth edition of the ECMAScript Language Specification. Since publication of the first edition in 1997, ECMAScript has grown to be one of the world's most widely used general-purpose programming languages. It is best known as the language embedded in web browsers but has also been widely adopted for server and embedded applications.
ECMA 2021
ECMAScript 2021, the 12th edition, introduces the replaceAll
method for Strings; Promise.any
, a Promise combinator that short-circuits when an input value is fulfilled; AggregateError
, a new Error type to represent multiple errors at once; logical assignment operators (??=
, &&=
, ||=
); WeakRef
, for referring to a target object without preserving it from garbage collection, and FinalizationRegistry
, to manage registration and unregistration of cleanup operations performed when target objects are garbage collected; separators for numeric literals (1_000
); and Array.prototype.sort
was made stable.
replaceAll
Assuming we have a constant named string
const string = "Javascript is the best web scripting language. Javascript can be used for both front end and backend";
and we want to replace the word Javascript
with Typescript
we normally would use the replace
method
const string = "Javascript is the best web scripting language. Javascript can be used for both front end and backend";
console.log(string.replace("Javascript", "Typescript"));
What if we want to replace all instances of Javascript
with Typescript
That is where the replaceAll method comes to shine
const string = "Javascript is the best web scripting language. Javascript can be used for both front end and backend";
console.log(string.replaceAll("Javascript", "Typescript"));
Private Methods
lets create a class named People
and we have will have some methods
class People {
showName() {
console.log("My name is Faithful")
}
showAge() {
console.log("Faithful is 20")
}
}
To access the methods inside the classes we first need to instantiate the class
class People {
showName() {
console.log("My name is Faithful")
}
showAge() {
console.log("Faithful is 20")
}
}
const people = new People()
people.showName()
people.showAge()
We can see that My name is Faithful
and Faithful is 20
gets logged on console.
if we want to make showAge() a private method inside the class People so outside the scope of the class it is not accessible
we just add the #
sign in front of the showAge
method like this #showAge
class People {
showName() {
console.log("My name is Faithful")
}
#showAge() {
console.log("Faithful is 20")
}
}
const people = new People()
people.showName()
people.showAge()
we can see the result on our console. An error is saying people.showAge
is not a function. This is because #showAge()
is now a private method inside the class People and can only be access via a public method in side the class People.
Now lets try and access the private method #showAge()
first we create new public method called showAll()
inside the class People from this public method we can access the private method #showAge()
and since our new method is a public one we would be able to print the age on the console. Take a look at the code below
class People {
showName() {
console.log("My name is Faithful");
}
#showAge() {
console.log("Faithful is 20");
}
showAll() {
this.showName()
this.#showAge();
}
}
const people = new People();
people.showAll();
we can see that the error has disappeared and we can now access our private method via a public one showAll()
Private Accessors
Private accessors work very similar to private methods lets create a class named People
and we have will have some methods
class People {
get Name() {
return "Faithful"
}
get Age() {
return 20
}
}
let people = new People();
console.log(people.Age);
We can see 20
gets logged on console.
if we want to make Age a private accessor inside the class People so outside the scope of the class it is not accessible
we just add the #
sign in front of the Age
method like this #Age
class People {
get Name() {
return "Faithful"
}
get #Age() {
return 20
}
}
let people = new People();
console.log(people.Age)
we can see the result on our console is undefined.
Now lets try and access the private method #Age()
first we create new public method called publicAge()
inside the class People from this public method we can access the private method #Age()
and since our new method is a public one we would be able to print the age on the console. Take a look at the code below
class People {
get Name() {
return "Faithful"
}
get #Age() {
return 20
}
get publicAge() {
return this.#Age
}
}
let people = new People();
console.log(people.publicAge)
we can see that the error has disappeared and we can now access our private accessor via a public one publicAge()
Promise.any()
Promise.any() is like the opposite of Promise.all()
. Promise.any() resolves if any of the supplied promised is resolved unlike promise.all()
which waits for all promises to resolve before it resolves.
lets take a look at the example below
Basically we have 3 promises that resolves at random times. We have used setTimeout()
function to set a time taken for each promise to resolve and we used Math.floor(Math.random) to give a random time to the setTimeout function so we really dont know which promise resolves first. This exaclty what happens in real world secenario.
const prom1 = new Promise((resolve, reject) => {
setTimeout(
() => resolve("this is the first promise"),
Math.floor(Math.random() * 100)
);
});
const prom2 = new Promise((resolve, reject) => {
setTimeout(
() => resolve("this is the second promise"),
Math.floor(Math.random() * 100)
);
});
const prom3 = new Promise((resolve, reject) => {
setTimeout(
() => resolve("this is the third promise"),
Math.floor(Math.random() * 100)
);
});
(async function() {
const result = await Promise.any([prom1, prom2, prom3]);
console.log(result); // Prints "A", "B" or "C"
})();
from the result in console, we can see that our second promise resolves first.
Wait! what if none of the promises resolve? Well, Promise.any() throws an AggregateError exception. We will handle it in a try catch block.
Take a look at the example below
const rejected = new Promise((resolve, reject) => {
setTimeout(
() => reject("this is the first promise"),
Math.floor(Math.random() * 100)
);
});
try {
(async function() {
const result = await Promise.any([rejected]);
console.log(result);
})();
} catch(error) {
console.log(error.errors);
}
Numeric Separators
This feature enables developers to make their numeric literals more readable by creating a visual separation between groups of digits. Large numeric literals are difficult for the human eye to parse quickly, especially when there are long digit repetitions.
1000000000 // Is this a billion? a hundred millions? Ten millions?
101475938.38 // what scale is this? what power of 10?
Examples
Regular Number Literals
let budget = 1_000_000_000_000;
// What is the value of `budget`? It's 1 trillion!
//
// Let's confirm:
console.log(budget === 10 ** 12); // true
Binary Literals
let nibbles = 0b1010_0001_1000_0101;
// Is bit 7 on? It sure is!
// 0b1010_0001_1000_0101
//
// We can double check:
console.log(!!(nibbles & (1 << 7))); // true
Hex Literals
// Messages are sent as 24 bit values, but should be
// treated as 3 distinct bytes:
let message = 0xA0_B0_C0;
// What's the value of the upper most byte? It's A0, or 160.
// We can confirm that:
let a = (message >> 16) & 0xFF;
console.log(a.toString(16), a); // a0, 160
// What's the value of the middle byte? It's B0, or 176.
// Let's just make sure...
let b = (message >> 8) & 0xFF;
console.log(b.toString(16), b); // b0, 176
// What's the value of the lower most byte? It's C0, or 192.
// Again, let's prove that:
let c = message & 0xFF;
console.log(c.toString(16), b); // c0, 192
lets view our result in console
Logical Assignment Operator
Logical Assignment Operator with &&
Logical assignment operator combines the logical operations(&&, || or ??) with assignment.
var x = 1;
var y = 2;
x &&= y;
console.log(x); // 2
Techincally here's what is actually going on
if(x) {
x = y
}
Since x
is a truthy value, it is assigned with the value of y
, ie 2
.
Just like the way we did with &&
, we can do with ||
and ??
.
x &&= y;
x ||= y;
x ??= y;
Logical assignment operator with ||
var x = 1;
var y = 2;
x ||= y;
console.log(x);
That means, the assignment operation happens only if x
is a falsy value. In our code, x
contains 1
which is a truthy value and hence, assignment does not happen. That is why our code prints 1
in the console.
Logical assignment operator with ??
??
is Nullish Coalescing operator in JavaScript. It specifically checks if a value is null
or undefined
.
var a;
var b = a ?? 5;
console.log(b);
In line 2, if the value of a
is null
or undefined
, the right hand side of ??
is evaluated and assigned to b
.
Let us now consider ??
along with =
.
var x;
var y = 2;
x ??= y;
console.log(x); //
Here the value of x
is undefined
. So the right hand side expression is evaluated and sets x
to 2
.
You can edit and test the code here
Top comments (15)
Great post, Faithful!
The numeric separators are extremely handy, love them. I'll be using private methods a lot.
By the way, if someone is asking why JavaScript uses the
#
symbol for its private properties and not theprivate
keyword, in this comment from the ECMA committee they explain why.Thanks for pointing that out I forgot to include that in this post.
Great Post !
Can you please explain the difference between
Promise.race and Promise.any ?
They booth act the same ? Does Promise.race have been deprecated ?
They are a bit different
Promise.race is resolved as soon as any of the promises you feed it resolves, whether they are fulfilled or rejected. Promise.any is settled as soon as any of the promises you feed it is fulfilled or all the promises are rejected. If all promises are rejected it returns an AggregateError.
So Promise.race returns a promise that is settled regardless it being resolved or rejected. But promise.any will not return if one promise is rejected. It will continue until the first resolved promise. If in any case none of the promises resolves then it returns an AggregateError.
I hope I cleared your confusion
Promise.race() isn't deprecated either.. They have different use cases
WHEN does Promise.any throw an error ? how can it know that none of the promise will be resolved later ?
did you mean that when ALL promises are rejected an exception is thrown ? that isn't exactly the same
When you use
Promise.any
, your literally saying which ever promise resolves first. It would only throw an error if non resolves.If you want to make sure all your promise resolves or you want to catch error when any of the promises is rejected you should use
Promise.all
insteadNice Post
Finally Promise.any solve my error handling easily! ( 0 )
Seems like I'll be using the replace all method frequently, and the numeric separators will come in really handy... A detailed, well written, explanatory post. Keep it up!
Very true the replaceAll method and the numeric separators were really needed.
I see myself using the private methods and accessors alot
Running the code above gives me Invalid character: '#'
Update your chrome browser if thats what you are using.
it was a great article thanks
Quite informative. I got to learn about the new operators, kinda tricky though, the Promise.all also looks very promising.