DEV Community

Cover image for ES2020: New Features & What's Beyond
Mihaela for WorksHub

Posted on • Originally published at javascript.works-hub.com

ES2020: New Features & What's Beyond

The world of JavaScript( officially ECMAScript ) changes fast and with awesome features getting added each year, it's certainly hard to keep up. The last big overhaul happened in ES2015 when a bunch of new features, sugarcoated syntax were added to the language.

ECMAScript community releases new features every year. In this post, we will have a look at 7 key features that were introduced in ES2020

  1. *Big Int *
  2. Nullish Coalescing Operator
  3. Optional Chaining
  4. Global this
  5. Promise.allSettled
  6. Dynamic Import
  7. String.prototype.matchAll

Let's get into each one by one

1. Big Int


BigInt is a special data type introduced in ES2020 to define numbers that exceed the Number data type range. The Number data type limits between -(2^53-1) to -(2^53-1), which we can check using
Number.MAX_SAFE_INTEGER & Number.MIN_SAFE_INTEGER.

console.log(Number.MIN_SAFE_INTEGER);
// -9007199254740991

console.log(Number.MAX_SAFE_INTEGER);
// 9007199254740991
Enter fullscreen mode Exit fullscreen mode

Introduction to BigInt now increases the total number of primitive data type to 8, the rest being,

  1. Undefined
  2. Null
  3. Number
  4. String
  5. Object
  6. Symbol
  7. Boolean

To use BigInt, we simply append n at the very end of an integer, and that would be parsed as a BigInt.

BigInt("1")    // -> 1n
typeof(1n)    // -> "bigint"
Enter fullscreen mode Exit fullscreen mode

a) BigInt Uses :

BigInt is useful in situations where we have to essentially deal with large integers that are beyond the scope of Number type.

console.log(18014398509481982n + 18014398509481982n)  // -> 36028797018963964n
Enter fullscreen mode Exit fullscreen mode

b) BigInt Operations :

All arithmetic operations are valid, the only exception to this is unary plus operator

console.log(1n + 1n)       // -> 2n
console.log(7n / 3n)      // -> 2n
console.log(+10n)     // -> Unary Operator error
Enter fullscreen mode Exit fullscreen mode

The same goes for comparison as well, however, strict equality doesn't hold when compared with the Number data type.

10n == 10 -> True
10n === 10 -> False
Enter fullscreen mode Exit fullscreen mode

2. Nullish Coalescing Operator


The Nullish Coalescing operator is not something new but rather a sugarcoated version of a pattern we have been doing for quite a long time.

Have a look at this piece of code :

if (a !== null && a !== undefined){
  return a;
}
else {
  return b;
}

// Now, nullish coalescing operator would simplify the above logic to :
a ?? b

Enter fullscreen mode Exit fullscreen mode

In simple terms,

_ ?? returns the first argument if it is defined i.e neither null nor undefined _

_ ?? returns the second argument if the first argument is either null or undefined _

Confused? Well let's have a look at few examples to clear up things

1 ?? 2  // 1 (returns the first argument as its neither null nor undefined)

undefined ?? 1  // 1 (returns the second argument as the first one is undefined)

// we can even chain up several arguments as well, and the operator would return the first `defined value`

var country = null;
var state = undefined;
var city = "London";

console.log(country ?? state ?? city) // London (returns the first `defined value`)

Enter fullscreen mode Exit fullscreen mode

Use case :

Let's say if a user is logged-in, display the first name else display "Anonymous" :

When logged-in
let user = "Alice"
console.log(user ?? "Anonymous"); // Alice

When not logged-in
let user = undefined;
console.log(user ?? "Anonymous"); // Anonymous
Enter fullscreen mode Exit fullscreen mode

3. Optional Chaining


The Optional Chaining Operator introduced in ES2020 is similar to the . (dot operator). It solves a very specific problem and is useful when we need a property that is nested deep in an object.

Consider the example below :

let response = {
    type : "customer",
    isSignedIn : true,
    details : {
        age : 22,
        name : "Lucy",
        Country : "Estonia"
    }
}
Enter fullscreen mode Exit fullscreen mode

Given the above example is an API response and we aren't sure if the property we are accessing even exists inside the object or not, then traditionally we have to do something like below to make sure we don't have any nullish value when nesting inside the response object properties

const data = response.details && response.details.name
Enter fullscreen mode Exit fullscreen mode

However, with Optional Chaining, we can do :

const data = response.details?.name
Enter fullscreen mode Exit fullscreen mode

JavaScript makes sure at each level of the object the property is not nullish (null or undefined), hence proving ?. much practical than plain ol' dot operator.

Gotchas with :
Optional Chaining throws an error on the left-hand side of an assignment.
The very first property before the ?. must be defined and cannot be invalid.
Similar to ?. we have slightly different variants too :

?.[] => calling arrays

?.() => calling functions

4. Global this


Think about the number of environments and platforms we run JavaScript in, browsers, smartphones, servers, robotics equipment.
For each environment, the JavaScript Object model is different and the global object might point to a different property.

In browsers, the global object could be window, self or frame, depending on the context. However there is no scope of the above-mentioned properties in NodeJs, hence it uses global to point to its global object.

Can we see the chaos here? If we have to run our js code in a range of different environment we need to figure out its global object first and is exactly what we have been doing for so long.

A common pattern to figure out the global object is as :

function getGlobalObject() {
  if (typeof globalThis !== 'undefined') { return globalThis; }
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('cannot find the global object');
};

if (typeof getGlobalObject().Promise.allSettled !== 'function') {
  // the Promise.allSettled() Not available in this environment
}

Enter fullscreen mode Exit fullscreen mode

However, the above solution has its own limitations and trade-offs.

globalThis tries to address the issue by pointing globalThis keyword to its global object model irrespective of the environment(as it is available everywhere). It was introduced in 2020 and currently stands on stage 4 and is available on most browsers.

// nodeJS
console.log(globalThis) // returns the global object
// browsers
console.log(globalThis) // returns the window object
// web-workers
console.log(globalThis) // returns the global web workers context

Enter fullscreen mode Exit fullscreen mode

With the introduction of globalThis, it would be best practice to stop using this keyword in the context of global objects and start using globalThis instead.

5. Promise.allSettled


Promise.allSettled() is a method that takes an iterable object(array) and returns a promise when all the provided promises have either resolved or rejected, meaning it does not short-circuit in the middle.

The returned outcome is an object with two things :

_a) value -> If the status is fulfilled._

_b) reason -> If the status is rejected._
Enter fullscreen mode Exit fullscreen mode

It's hard not to talk about the ES2015's Promise.all and its similarities/dissimilarities with allSettled
A striking difference between these two would be all short-circuits in the middle if any of the provided promises is rejected, while allSettled waits for async result and filters them by status and never shortcircuits.

Let's have a look at its working :

const promise1 = new Promise((resolve) => resolve("yay"));
const promise2 = new Promise((resolve, reject) => reject("oh-no"));


    (async () => {
     try {
     const result = await Promise.allSettled([promise1, promise2]);
     console.log(result);
     } catch (error) {
     console.error(error);
     }


    })();
 // Output:
 // [
 // { status: 'fulfilled', value: 'yay' },
 // { status: 'rejected', reason: 'oh-no' },
 // ]
Enter fullscreen mode Exit fullscreen mode

If we compare it with all :

const promise1 = new Promise((resolve) => resolve("yay"));
const promise2 = new Promise((resolve, reject) => reject("oh-no"));


    (async () => {
     try {
     const result = await Promise.allSettled([promise1, promise2]);
     console.log(result);
     } catch (error) {
     console.error(error);
     }
     })()

 // Output:
 // Error : "oh-no" 
Enter fullscreen mode Exit fullscreen mode

6. Dynamic Import


The amount of JS heavy apps we ship these days can be quite overwhelming and with these lot of javascript files, the module import/export should be effective.

ES2020's dynamic import addresses this issue to make the page load ups, first meaningful paint etc efficient and fast.
This is done by dynamically importing the files that we need at that point in time.

The import keyword was introduced in ES2015, and we have been importing modules like

import React from 'react';
Enter fullscreen mode Exit fullscreen mode

ES2020 allows us to use import as a function (although it looks like a function, it is not)

// we dont need to set type of module below
<script>
  import('./add.js')
    .then(module => module.default(3, 7)) //returns 10
    .catch(error => // log error here);
</script>
Enter fullscreen mode Exit fullscreen mode

The above piece of code makes sure the add.js module is only imported when we need to sum up two numbers. It doesn't unnecessarily bloat up the js code which could make page loads slow.

7. String.prototype.matchAll


matchAll is a new method that is added to the string prototype. This returns an iterator matching against a regular expression that we have given.

A simple example to demonstrate the same :

const test = "climbing, oranges, jumping, flying, carrot";

const regex = /([a-z]*)ing/g;

const matches = [...test.matchAll(regex)];

const result = matches.map(match => match[1]);

// outputs the following :
["climb", "jump", "fly"]
Enter fullscreen mode Exit fullscreen mode

While we just finished learning ES2020, the ES2021 has already been drafted for its next release. Here's what's in the box for us :

  1. String.prototype.replaceAll
  2. Promise.any
  3. Logical Operators and Assignment Expressions
  4. Numeric Separators
  5. WeakRefs
  6. Intl.ListFormat

*Some Important Resources that I have collected over time: *

i. https://auth0.com/blog/javascript-whats-new-es2020/

ii. https://www.martinmck.com/posts/es2020-everything-you-need-to-know/

iii. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

iv. https://blog.tildeloop.com/posts/javascript-the-difference-between-match-and-matchall

Loved this post? Have a suggestion or just want to say hi? Reach out to me on Twitter

Originally written by Abhinav Anshul for JavaScript Works

Discussion (0)