All the new features of ECMAScript 2020 (ES2020) or ES11

ECMAScript 2020/ ES11 all new features

  • ECMAScript 2020 or ES11 brought some exciting new features such as private fields in classes, optional chaining, nullish coalescing operator, and BigInts.
  • Matching of a string with a regular expression is now simplified and more impressive with the introduction of the String.prototype.matchAll() method.
  • Promises in JavaScript either fulfilled or rejected, can now be managed elegantly by Promise.allSettled().
  • And finally, our dilemma of this keyword in various environments would be no longer a headache thanks to globalThis. 

After the introduction of ES6 in 2015, JavaScript has been developing rapidly with lots of new functionality emerging out of each version. Current versions of the JavaScript language specification have been revised regularly, with the latest new language functionality being finalized more rapidly than ever before, which means that new functionalities are being integrated into mainstream browsers and other JavaScript run-time engines, such as Node.js, at a pace that we've never seen before.

In 2019, there were a number of new features in the' Step 3' stage, which meant they were really close to being final, and the browsers/node now started getting support for such updates. If we want to use them for development, we can use anything like Babel to convert it to older versions of JavaScript so that it can be used in older browsers such as Internet Explorer if required.

ES2020 is the ECMAScript edition released in the year 2020. However, this edition is not jam-packed with as many new features as those that existed in ES6 (2015). Nevertheless, a variety of valuable functions have been implemented.

We discuss all of the major ES2020 features with simple examples to better understand them which is a good way to learn new concepts without facing any complexities. So don't wait anymore and let's get started. 

New ECMAScript 2020 or JavaScript ES11 features 

  • String.prototype.matchAll
  • Dynamic import()
  • BigInt
  • Private Fields in Classes
  • Promise.allSettled
  • Nullish Coalescing Operator
  • The for-in mechanism in JS
  • Optional Chaining Operator
  • globalThis

String.prototype.matchAll()

This method is not completely new but since the new update in the latest ES11, we are having a good time when matching a string against a regular expression, including capturing groups.

Let's have a look at a simple example

const regexp = RegExp('foo[a-z]*','g');
const str = 'table football, foosball';
const matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(`Found ${match[0]} start=${match.index} end=${match.index + match[0].length}.`);
}
// expected output: "Found football start=6 end=14."
// expected output: "Found foosball start=16 end=24."

// matches iterator is exhausted after the for..of iteration
// Call matchAll again to create a new iterator
Array.from(str.matchAll(regexp), m => m[0]);
// Array [ "football", "foosball" ]

Dynamic Imports with import()

Earlier, we need to import files from which the JavaScript Engine read the modules and bring them to our current file where those functionalities are being called. Imagine if you had a file full of utility programs, some of them could never be used, so adding all their dependencies could just be a waste of time. Perhaps we can now use async / wait to dynamically import our dependencies when we need them.


import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
This is how modules worked, which were introduced in the ES6. And it was pretty handy to import files statically.


const doMath = async (num1, num2) => {
  if (num1 && num2) {
    const math = await import('./math.js');
    console.log(math.add(5, 10));
  };
};

doMath(4, 2);
This type of dynamic import returns a promise for the module specified. After this thing becoming real, a number of possibilities open up now that can be explored.


BigInt

Developers suffered while adding two really big numbers ultimately causing an overflow. We're not going into the technical details, but considering JavaScript's way of handling numbers, when things are going high enough, it starts to get a little creepy. The largest number that JavaScript can handle is 2 ^ 53, which can be seen with MAX_SAFE_INTEGER. Beyond this, things start to get jumbled up.

With the new BigInt data type, we can get rid of these anomalies. By casting the letter' n' at the end, we can start embracing extremely large numbers. We're not able to interweave standard numbers with BigInt numbers so that math needs to be done with BigInts as well.

const bigNum = 100000000000000000000000000000n;

console.log(bigNum * 2n); // 200000000000000000000000000000n
Unfortunately, however, you can't actually augment a BigInt with a float number. And you can't use the BigInt with a Number together, at all. The only way to mix the types is when you are comparing two values. A BigInt can also be recognized as a number if it's in a 'if' condition.

Private Fields in Classes

A totally fresh concept in ES2020  is a way to add private variables to classes, just by using the #sign to indicate that the class variable is a private variable. This way, we don't have to use closures to hide private variables that we don't decide to expose to the global scope. For example, we can write a simple class to increment and decrement data such as the following code:

class Counter {
  #x = 0;
  increment() {
    this.#x++;
  }
  decrement() {
    this.#x--;
  }
  getNum(){
    return this.#x;
  }
}
const c = new Counter();
c.increment(); 
c.increment(); 
c.decrement(); 
console.log(c.getNum());
From the console.log statement in the last line, we will obtain 1 as our result. #x is a private variable that is exclusively available inside the scope of the class. Private variables are a much anticipated JavaScript class feature. This function is now ready to use in the latest version of Chrome and Node.js v12.

Promise.allSettled

While operating on multiple promises, particularly when they rely on each other, it could be helpful to log what happens to each debug error. With Promise.allSettled, we will make a new promise that will only return after all the promises made are fulfilled. This will allow us access to an array of data on every promise.

This is identical to Promise.all, but there is a major distinction between them. Promise.all holds until all the promises are fulfilled or refused. On the other side, Promise.allSettled doesn't even care for that. It just makes sure that all the promises are accomplished, whatever their status may be. So any input promise may be fulfilled or refused, it doesn't matter to Promise.allSettled. Both of them have to be finished.


const p1 = new Promise((res, rej) => setTimeout(res, 1000));

const p2 = new Promise((res, rej) => setTimeout(rej, 1000));

Promise.allSettled([p1, p2]).then(data => console.log(data));

// [
//   Object { status: "fulfilled", value: undefined},
//   Object { status: "rejected", reason: undefined}
// ]

Nullish Coalescing Operator

Since JavaScript is dynamically typed, you may need to keep JavaScript's treatment of true/false values into consideration while assigning variables. If we have an entity with certain values, often we want to accept values that are technically incorrect, like an empty string or 0. Setting default values easily becomes irritating, as it overrides what true values should be.

When executing property accesses, a default value is always required if the outcome of the property access is null or undefined. Currently, the usual way to convey this purpose in JavaScript is to use the || operator.

For example, if we have:

const y = x || 100;

Here, we have to set a default value in case x is undefined when it is set to y by using the || operator. The trouble with the || operator is that all erroneous values like 0, false, or null strings are overridden with the default value that we don't really want to do.
 
To overcome this, there was a suggestion to set up a "nullish" coalescing operator, which is denoted by??. In it, we only set the default value if the first element is either null or undefined. For example, with the null and void coalescing operator, the expression above would be as follows:


const y = x ?? 100;

Instead of || operator, we may use the dual question mark operator to be a bit more specific form, which only makes the default if the value is null or unknown. Sadly, this feature is not supported by any browser, nor by Node.js yet, and thus, we need to use the latest version of Babel to implement this functionality.

The for-in mechanism in JS

Standard ECMA-262 leaves the order for (a in b)... almost completely unspecific, but in real working environments, engines appear to be specific in at least certain instances.

Historical attempts to find a consensus on a full specification of the order of for -in have often failed, partially because all engines have their own peculiar configurations, which are the product of a lot of work and which they just do not want to reconsider. In addition, various engines have settled on how the properties are iterated by using the control scheme (a in b) so that the behavior is consistent.

Optional Chaining Operator in JS

Usually, if we want to reach an object's deeply nested properties, we need to test whether the properties at-nesting stage is defined by long boolean expressions. Similar to the null and void coalescing function, JavaScript can not behave as we like when dealing with faulty values. We can return a value if what we want to obtain is not known, but what if the route to it is not defined?

Appending a question mark to our dot notation, we can make certain aspects of the value's path optional so that we can still communicate with it. The Optional Chaining Operator allows all of these scenarios to be treated without repeating themselves and/or assigning intermediate outcomes to temporary variables.

let person = {};

console.log(person.profile.name ?? "Anonymous"); // person.profile is undefined
console.log(person?.profile?.name ?? "Anonymous");
console.log(person?.profile?.age ?? 18);

globalThis object in JS

Until ES10, this conceptual object was not standardized. This concept is pretty straightforward and easy going. 

globalThis refers to the global this context on which your running context is. If you’re on Browsers, globalThis will be this, if you’re on Node, globalThis will be global. Hence, no need to think about environmental clashes anymore.


// worker.js
globalThis === self

// node.js
globalThis === global

// browser.js
globalThis === window

Concluding words

JavaScript is a dynamic language, so it's a very positive thing for web development. Since the ES6 was released in 2015, we have been witnessing a lively development of the language. In this article, we checked out some of the features of the ES2020.

ES2020 certainly packs loads of new features. Some of them, however, do not support old browsers, so they are not always stable in any environment. And you should know that in what environments you will have to watch out for.


Post a Comment

Thank you! Your comment has been sent to moderation and will be published soon after passing the moderation test.

Previous Post Next Post