DEV Community

loading...
Cover image for JavaScript new features in ECMAScript 2021

JavaScript new features in ECMAScript 2021

Muhammad Bilal Bangash
I am a Full Stack developer. I specialized in React JS, Next JS, Node JS, Gatsby, JavaScript, Angular, GraphQL. I'm passionate about new technologies and I keep learning all the time.
Updated on ・4 min read

Below are some new features that you can expect from the ECMAScript:

  • replaceAll
  • Promise.any
  • WeakRefs and finalizer
  • Logical Assignment Operators
  • Numeric separator

Let's begin with the first one.

1. replaceAll() method

The replaceAll() method allows you to replace all occurrences of a substring with another string that you defined. Currently, the replace() method only replace the first occurrence of the substring while ignoring the rest:

const str = 'How+are+you?';
const addSpaces = str.replace('+', ' ');
console.log(addSpaces); // How are+you?
Enter fullscreen mode Exit fullscreen mode

The only way to replace all occurrences is to use replace() with a global regular expression as follows:
// replace all '+' with a 'space'

const str = 'How+are+you?';
const addSpaces = str.replace(/\+/g, ' ');
console.log(addSpaces); // How are you?
Enter fullscreen mode Exit fullscreen mode

With the replaceAll() method, you don’t have to use a regular expression anymore:

const str = 'How+are+you?';
const addSpaces = str.replaceAll('+', ' ');
console.log(addSpaces) //How are you?
Enter fullscreen mode Exit fullscreen mode

2. Promise.any()

The Promise.any() method returns a promise that will resolve as soon as one of the promises are resolved. If all of the promises are rejected, the method will throw an AggregateError exception holding the rejection reasons.
Here’s an example:

const firstPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("First Promise Fulfilled"), 3000);
});
const secondPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Second Promise Fulfilled"), 2000);
});
const thirdPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Third Promise Fulfilled"), 1000);
});
Promise.any([firstPromise, secondPromise, thirdPromise]).then(
  (promiseFulfilled) => {
    // Any of the promises was fulfilled.
    console.log(promiseFulfilled); // Third Promise Fulfilled
  },
  (error) => {
    console.log(error)// Error Handling
  }
);

Enter fullscreen mode Exit fullscreen mode

If all of the promises given are rejected, the AggregateError exception will be thrown.
Here’s another example showing the exception using the async/await syntax:

const firstPromise = new Promise((resolve, reject) => {
  setTimeout(() => reject(), 1000);
});
try {
  const first = await Promise.any([firstPromise]);
  // Any of the promises was fulfilled.
} catch (error) {
  console.log(error);
  // AggregateError: All promises were rejected
}
Enter fullscreen mode Exit fullscreen mode

3. WeakRefs

The WeakRef, which stands for Weak References, allows you to create a weak reference to an object. The primary use of Weak Reference is to implement caches or mappings of a large object.
A regular/ strong JavaScript object reference will never be claimed by the garbage collector. A weak reference to an object, in contrast, can be claimed by JavaScript garbage collector:
const simpleObj = {name: "John Doe"};
const referenceObj = new WeakRef({name: "John Doe"});

When you need to read the value of WeakRefs , you need to use the deref() method to return the instance’s target object:

const referenceObj = new WeakRef({name: "John Doe"});
const obj = referenceObj.deref();
console.log(obj.name); // John Doe
Enter fullscreen mode Exit fullscreen mode

Because the implementation detail of when, how, and whether JavaScript garbage collection actually occurs or not is up to the JavaScript engine implementation, you may observe different behavior between one JavaScript environment and another.
The correct use of WeakRef takes careful thought, and it’s best to avoid implementing one if possible. Unless you’re a JavaScript library maintainer, you will most likely never need to use it.

4. Finalizers

The Finalizer is a companion feature of WeakRef that allows you to execute a piece of code after an object has become unreachable to the program.
In short, you can register a callback function that gets triggered after the garbage collection occurs. You can create a registry by passing the callback to the FinalizationRegistry object:

const registry = new FinalizationRegistry(value => {
  console.log(value);
});
Enter fullscreen mode Exit fullscreen mode

Then, you can register any object you want to cleanup for by calling the register() method, passing both the object and the value you want to pass to the callback function:
registry.register({name: "John"}, "any value");
The object passed into the register() method will be weak-referenced so that it can be garbage collected. Based on the code above, the callback will log “any value” to the console.
Both WeakRefs and Finalizers are tricky concepts. You can learn more about weak reference and FinalizationRegistry.
WeakRef
FinalizationRegistry

5. Logical assignment operator

The logical assignment operator combines Logical Operators and Assignment Expressions, allowing you to write a shorter syntax for variable value checking.

For example, the following code checks whether the value of x is falsy and only assign a new value when it is:

let x;
if(!x){
  x = 7;
}
Enter fullscreen mode Exit fullscreen mode

Using the logical assignment operator, you can replace the above code with the following:

let x;
**x ||= 11;** // since x is undefined, it's assigned the number 11
console.log(x); // 11
The logical assignment works with logical AND (**&&**) and nullish coalescing operator (**??**) as well:
let x = null;
x ??= 11 // assign 11 to x when it's null or undefined
let y = "JavaScript";
y &&= 11 // assign 11 to y when it's value is truthy

Enter fullscreen mode Exit fullscreen mode

6. Numeric separator

The numeric separator proposal helps you to write more readable code by allowing you to use underscore (_) as a separator when you define a numeric value.
The following code shows the comparison between a normal number and a separated number for one million:


const oneMillion = 1000000;
const separatedOneMillion = 1_000_000;
console.log(separatedOneMillion); //1000000

Enter fullscreen mode Exit fullscreen mode

As you can see, separating the number with an underscore makes it much more readable. You can even use it on numbers with floating points as follows:

const randomFloat = 4.11_857_111_1211;
console.log(randomFloat) //4.118571111211
Enter fullscreen mode Exit fullscreen mode

The separator won’t be included when you use the value for operations:

const randomFloat = 4.7_857_123;
console.log(randomFloat); // 4.7857123
Enter fullscreen mode Exit fullscreen mode

Imported Note that you can only use the separator between two digits:

const num = 4_111; // 4111
// All the below throws an error
const a = 47_; //Uncaught SyntaxError: Numeric separators are not allowed at the end of numeric literals
const b = _11;//Uncaught ReferenceError: _47 is not defined
const c= 7._11;Uncaught SyntaxError: Invalid or unexpected token
Enter fullscreen mode Exit fullscreen mode

Discussion (4)

Collapse
pkumar2991 profile image
pkumar2991

Well explained. thanks buddy

Collapse
furkanulutasx profile image
Furkan

Very nice. thanks.

Collapse
meyashtiwari profile image
Yash Tiwari

Great article man, thanks a lot for the explanation.