DEV Community

Cover image for What’s new in ES2020 (ES11)?

What’s new in ES2020 (ES11)?

hanakivan profile image Ivan Hanák ・8 min read

Hey guys! 👋

It’s been a couple of weeks (or months already 😌) since the new major update of JavaScript has been released, but if you haven’t had the time to check it out yet, I invite you to join me here in this article where I will show you what’s new, what’s changed and I’ll also include screenshots and my thoughts of how the new features can be used.

Ready? So let’s dive right in! 🤘

Table of contents:

  1. Integers larger than a quadrillion
  2. Native browser module dynamic import
  3. Operators
    • Nullish Coalescing Operator
    • Optional Chaining Operator
  4. Promise.allSettled
  5. String.prototype.matchAll
  6. Global variable window replacement
  7. Named module exports
  8. Import meta

1. Integers larger than a quadrillion

First of all, this is very interesting update, but lots of programmer will probably never-ever need an integer this big. But in my opinion, still worth knowing 😉.

Currently, the largest integer you can get in JavaScript is 9007199254740991 or 2⁵³ - 1 or JavaScript has a special constant for that, i.e. Number.MAX_SAFE_INTEGER.

What’s the problem with it?

Well, look at the comparison below. Strangely, it evaluates to true 🤔 (try it in the web console)

//this evaluates incorrectly to true
9007199254740991 + 1 === 9007199254740991 + 2

That means working with really large integers is unsafe in JavaScript, because it will produce incorrect results.

Or at least it had been unsafe up until the ES2020 was released. From that moment on simply said it is not a problem at all 🤘 .

That’s why introducing: BigInt

So this problem was solved by creating a new built-in object in JavaScript called BigInt. You can use this new data type simply by appending a letter n to the number. It works like on the example below:

const iAmBigInt = 1n;
const iAmEvenLargerInt = 9007199254740991n * 9007199254740991n * 9007199254740991n;

const youAreSoHuge = BigInt(9007199254740991); // => produces 9007199254740991n

//this evaluates now correctly to false
//9007199254740991n + 1 === 9007199254740991n + 2

As you can see, it looks really strange. because it is just an integer with a letter n appended 😃 – but don’t worry, that’s correct and you will need just get used to it.

Interesting, right? If you want to learn more about this, check out way more comprehensive guide on MDN:

2. In-browser dynamic module import

I really admire people behind ECMAScript® for all the work they’ve done so far. Not so long ago it was possible to use import/export directives directly in browsers without compiling code via babel, then it was possible to dynamically load those modules only via webpack’s lazy loading and code splitting – and now, this is implemented in browser. By default. Yays! 🥳

You know what? Let’s got quickly for an example so you will see the magic.

Check out the example below:

export const multiply = (a, b) => (
    a * b

<!DOCTYPE html>
      <!-- ... -->
        <script type="module">
            document.body.addEventListener("click", async e =>{ 
                const {multiply} = await import("/module.mjs"); 
                console.log(multiply(1, 2)) });

As you can see, you don’t have to load all of the modules during the initial page load, but only after a specific action has been done by the user.

So the user experience and page load will be affected positively in a large scale, don’t you think? 🙂

Wanna see more? Check out really good article on MDN about this topic:

3. Operators

Get ready, you’re gonna absolutely looove this update! 😍

For quite a time we would have used those two operators, i.e. ?? and ?. only when having our code preprocessed by babel or similar code transpiler, but guess what, they work in-browser by default!

Let’s have a closer look at them:

3.1 Nullish Coalescing Operator

Year, really 🧐 strange name, but don’t worry. You’re gonna be using it all the time.

So, what’s this operator all about?

In order to understand nullish coalescing oeprator, you need to be aware of Logical OR operator or commonly known as || (yes, just two vertical pipes 😆) – because they are used in the same way and can be confusing.

So, seeing those two operators in action looks like this:

const first = "" || "not-empty-string";
const second = "" ?? "not-empty-string";

console.log(first); // => prints "not-empty-string"
console.log(second); // => prints ""

So, are you confused now? Told ya! 😁


Don’t worry, this is very, very simple.

OR operator:
  • || two vertical pipes
  • if the first value is “falsy” it will proceed to assigning the second variable

Nullish operator:

  • ?? two question marks
  • if the first value is null or undefined, it will proceed to assigning the second variable

The difference is in the first value. Simply, one operator checks for falsy values and the second one only for null or undefined.

I recommend you check out an article on MDN what does it mean falsy in JavaScript – in order to fully grasp this operator and also you’ll understand way more of JavaScript that way 🙂.

3.2 Optional Chaining Operator

Now, if the previous operator did not stirred enough water, this one definitely will!

And this operator can be quickly understood by an example, so check out the example below:

const users = [
        name: "Frederyk",
        age: 47,
        name: "Drew,
        age: 33,
        avatar: {
            id: 34,
            sizes: {
                thumb: {
                    src: "https://..."

//now the fun begins :D
users.forEach(user => {
    if(typeof user.avatar !== "undefined") {
        if(typeof user.avatar.sizes !== "undefined") {
            if(typeof user.avatar.sizes.thumb !== "undefined") {
                //...and you can really continue

    //calling this directly would break your code once it would get to the second iteration

Those never-ending checks, if the object has nested objects are really necessary, because otherwise your code might break, if there is a key missing.

And in order for us not to have to do those checks for undefineds, there is this new operator called optional chaining operator or just ?. Basically what it does it removes the necessity to use all of those checks, whether nested objects exists and it will do it for us.

For example, if we get back to the example above, it can now be shortened to:

const users = [
        name: "Frederyk",
        age: 47,
        name: "Drew,
        age: 33,
        avatar: {
            id: 34,
            sizes: {
                thumb: {
                    src: "https://..."

users.forEach(user => {
    //if there is no avatar object, this will result just in an undefined

Do you agree with me this operator will really change and simplify our code writing? 😎

You can study this operator in more depth again on very comprehensive documentation on MDN:

4. Promise.allSettled()

Let’s move on a bit, this time let’s talk a bit about promises.

This update will be probably used very rarely, but once you need to use it you will be really grateful it does exists; so let’s look at an example, of how we might use this.

Say, for example you are creating an image uploader. Your upload process will look like this:

  1. user drops images into the dropzone
  2. a loader will be shown
  3. your code will start uploading images
  4. once it finishes, show a successful message to the user and hide the loader

How would you go about the last step? Maybe store a number of currently running uploads somewhere in a variable and after each finished upload check, if everything has been uploaded? Or maybe use async/await and just loop through them?

Well, you can employ another approach, consider the example below:

const promises = [];

const promise1 = new Promise(async (resolve, reject) => {
     // some processing 

const promise2 = new Promise(async (resolve, reject) => {
    // some processing

Promise.allSettled(promises).then(results => {
    //once all of the promises has been resolved, this code will be called
    results.forEach(result => {

Quite interesting, right? 😉

I will end up talking about promises with the link for more information as well:

5. String.prototype.matchAll

egular expressions had their share in ES2020 as well. In particular, it was a new String‘s method, i.e. .matchAll().

What is does is basically it returns an iterator, which gives you all of the information about captures as well.

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."

As opposed to .match() it gives you full information about the match with its start and end index.

The whole thing could have been accomplished with Regex.prototype.exec() method, but it was a bit complicated.

If want to know more information about the .matchAll() method, take a look at the very comprehensive article on MDN:

6. globalThis

Are you writing JavaScript for Node? Also for browsers? Then you know probably the struggles with a global variable window – which is basically unavailable anywhere else but in the browser only.

And in order to unite this part of JavaScript, there is a new variable called globalThis, that basically does the following:

  • in the browser refers to window
  • in the service workers refers to self
  • in Node refers to global

So instead of doing this: (the example borrowed from

var getGlobal = function () {
    if (typeof self !== 'undefined') return self; 
    if (typeof window !== 'undefined') return window;
    if (typeof global !== 'undefined') return global;

    throw new Error('unable to locate global object');

const globals = getGlobal();
if (typeof globals.setTimeout !== 'function') {
    // no setTimeout in this environment!

To learn more about globalThis, please refer to more detailed article on MDN:

7. Named module exports

In JavaScript, import and export statements were very similar.

It is also more convenient for a programmer to know, that with the same way he is exporting stuff, she would do the same when importing.

But it was not quite true.

Let’s look at the example below:

export default "string";
import item from 'module.js';

export const price = 10;
import {price} from 'module.js';

They look identical, don’t they?

Now consider the example below:

export const price = 10;
export default class TestClass {}

import * as utils from 'module.js';

Now if you had wanted to accomplish something like this:

// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';

…it would not be possible up until now, but ES2020 made the named export possible 😊.

8. Import.meta

When using Javascript modules, within the modules it is possible to use a variable import.meta that will give you a URL on which the module is imported and used.

I personally have no idea how would I use this feature.

But I guess it can be very useful if you want to track on which sites is your module loaded.

Final thoughts

That’s it guys 🙌 . ES2020 is here and it is ready to be used. Currently every single feature is available in Chrome browser to be used without compiling – and that’s quite awesome, right? 😎

If you would like to learn more about the features mentioned above, follow the links where you can get even more details:

And also if you liked this article, don’t forget to share it with people you like (or maybe also people you don’t like, maybe you’ll became friends! 😆 ).

It is only matter of time ’till we see some exciting news again so if you want to be amongst the very first ones to hear about them, subscribe to my newsletter right here.

Anyways, thanks for reading and I’ll see you in the next article! 🤓

Yours in coding,



Editor guide