Linda Ikechukwu Frontend developer. Writer. Community Strategist. Building web interfaces that connect products to their target users.

New ES2021 features you may have missed

4 min read 1232

New Es2021 Features

For those who do not know, TC39 is the organization behind the standardization of the ECMAScript (JavaScript) specification. Ever since the major 2015 ES6 release, it has become the norm to release new features yearly.

For a feature to be added to a yearly release, it has to go through four proposal stages, with the final stage being approval. Let’s take a look at the five feature proposals that are currently in the final stage, with an anticipated release date for mid-2021.

1. Logical assignment operators

The new logical assignment operators &&=, ||=, and ??= are quite similar to the existing logical operators and are quite useful for assigning default values to variables.

Logical OR assignment operator (||=)

x ||= y

The logical OR assignment operator is a short-circuit operation just like the logical OR operator (||). The expression above is identical to x || (x = y), which means that y will only be assigned to x if x is falsy. Otherwise, x retains its original value.


const giveKey = () => {
  //perform randon computations
  return "somekey";
let userDetails = {name:"chika", age:5, room:10, key:""}
userDetails.key ||= giveKey()

//output : somekey

console.log(userDetails.key) returns "somekey" because the original key value was an empty string, which is a falsy value.

Logical AND assignment operator (&&=)

x &&= y

The logical AND assignment operator is the opposite of the logical OR assignment operator. In this case, y is only assigned to x, if and only if x is a truthy value. Otherwise, it retains its original value.


const deleteKey = () => {
  //perform randon computations
  return " ";
let userDetails = {name:"chika", age:5, room:10, key:"990000"}
userDetails.key &&= deleteKey()

//output : ""

userDetails.key &&= deleteKey() returns an empty string from the deleteKey function because the previous value of userDetails was a number, which is a truthy value.

Logical nullish assignment operator (??=)

x ??= y

The logical nullish operator only assigns y to x if x is nullish (i.e., either null or undefined).


const getKey = () => {
  //perform randon computations
  return "somekey";
let userDetails = {name:"chika", age:5, room:10,}
userDetails.key ??= getKey()

//output : "somekey"

Here the output is "somekey" because userDetails.key does not exist in the response object (i.e., it is undefined).

2. String.replaceAll

const newString = oldString.replaceAll(pattern, replacement);

The replaceAll method returns a new string in which all occurrences of a pattern are replaced by a replacement passed to it. The pattern parameter can either be a string or a regex pattern, and the replacement can either be a string or a function that creates a new string to replace the pattern.

The replaceAll method is a sequel to the String.replace method, which only replaces the first occurrence of the pattern with replacement.


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

3. Numeric separator

The numeric separator simply improves the readability of large numbers by using the underscore (_) character to separate number groups, just like you use commas to separate numbers in writing. Consider the number 1200044555. At first glance, it’s quite difficult to decipher that this number is 1.2 billion and something.


const billGatesNetWorth = 1_200_044_555;

Now this is much more readable. Note that this doesn’t have any performance benefits or affect equality. 1_200_044_555 is still equal to 1200044555.

4. Promise.any

Promise.any([promise1, promise2, promise3, ...]).then( something)

The Promise.any() method is a new promise method that takes in a series of promises and resolves to the value of the first promise to successfully resolve. In other words, the Promise.any resolves successfully if any of the promises resolve and rejects if all promises reject.


const promise1 = new Promise((resolve) => setTimeout((resolve) => resolve, 300, 'faster');
const promise2 = new Promise((reject) => setTimeout( (reject) =>reject, 100,"fastest")
const promise3 = new Promise((resolve) => setTimeout( (resolve) => resolve,700,'fast');
const promises = [promise1, promise2, promise3];


//Output: faster

5. WeakRef

const weakRef = new WeakRef({

//output: Linda

WeakRef is an advanced feature that should probably be avoided, according to the TC39 proposal notes. To understand what WeakRef does, you need to first understand the concepts of object referencing and garbage collection in JavaScript.

const obj = {}

When you create an object in JavaScript and assign it to a variable, the JavaScript engine running on a browser allocates a memory address that stores the object. On the other hand, the variable to which the object is assigned stores the memory address of the object and not the value of the object itself. So, you can say that obj holds a reference to the object assigned to it.

As objects are created and stored in memory, at some point, the browser may start to run out of memory and will need to free up memory space. Garbage collection is the process through which the browser engine frees up memory space by deleting objects that are no longer referenced by any variable.

WeakRef creates a weak reference to the the object passed to it. This means that whenever the browser needs to run garbage collection, if the only reference to that object is from a WeakRef variable, the JavaScript engine can safely remove the object from memory and free up space. This could be ideal for WebSocket data because of their short lifespans.

A WeakRef is created with the new WeakRef constructor, and the value of the WeakRef variable can be accessed via the deRef method.

How to start using ES2021 features in your codebase today

The new ES2021 features are already supported by recent versions of major browsers like Chrome 85, Firefox 79, and Safari 14. However, to enable your code to run in older browsers, you need to set up your project with the Babel complier.

Install the following packages:

npm install --save-dev @babel/core @babel/cli @babel/preset-env 
npm install core-js

Create a babel.config.json file at the root of your project:

    "presets": [
                "useBuiltIns": "usage",
                "corejs": {
                    "version": "3.8",
                    "proposals": true

The config above instructs Babel to use the env preset, which contains transforms for all the latest JavaScript features that have made it to stage four of the TC39 proposal process. It also instructs Babel to retrieve polyfills when needed from core JS.

Create a .browserlistrc file at the root of your project to specify the target browsers for Babel to transform code in:

maintained node versions

The defaults query instructs Babel to transform and polyfill code only for:

  • Browsers of the last two versions
  • Browsers with >0.5 percent marketshare usage
  • Browsers that are not dead

maintained node versions states that Babel should transform and polyfill code for all Node versions that are still maintained by the Node.js foundation.

Now, you can run:

./node_modules/.bin/babel src --out-dir lib

This will parse and transform all your JavaScript files in the src directory into code suitable for older browsers (as specified by your .browserlistrc file) and output each file to the lib directory.

N.B., if you’re using a toolchain like Create React App or vue-cli, these configurations are already abstracted.

And that’s it. You’re good to go. Go and start using ES2021 today!

: Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

Linda Ikechukwu Frontend developer. Writer. Community Strategist. Building web interfaces that connect products to their target users.

3 Replies to “New ES2021 features you may have missed”

  1. Hi, thanks for writing this good article, I love it.

    However I want to propose a correction for Promise.all in Promise.any part, The Promise.all should be reject if any of the promise rejected and resolve if all promise resolved.

    Keep writing good stuff.

  2. “`
    const promise1 = new Promise((resolve) => setTimeout((resolve) => resolve, 300, ‘faster’);
    const promise2 = new Promise((reject) => setTimeout( (reject) =>reject, 100,”fastest”)
    const promise3 = new Promise((resolve) => setTimeout( (resolve) => resolve,700,’fast’);

    This promise code is just completely wrong, even if you fix the missing closing brackets. Your `setTimeout` calls take a `resolve => resolve` callback, but this reject is not the one from the promise, it’s an internal parameter of the callback. You might as well have passed the callback `foo => foo` , and it will have the same result.

    `promise2` even renames the “resolve” parameter as `reject`. Further adding to the wrongness.

    I believe you meant:

    const promise2 = new Promise((_, reject) => setTimeout(reject, 100,”fastest”));

Leave a Reply