7 New Features Shipping With ES2020

GlobalThis, optional chaining, private fields in classes, the nullish coalescing operator, and more

Thomas Guibert
Mar 10, 2020 · 5 min read
Image for post
Image for post
Photo by Tomasz Frankowski on Unsplash

As you might know, since ES6 in 2015, a new version of ECMAScript is released each year, by Ecma International’s TC39. ECMAScript 2020 is the 11th edition of the ECMAScript Language Specification.

This new iteration comes with its own batch of new features — let’s review them!

1. ‘globalThis’

The JavaScript language is quite popular now and can be used in a wide variety of environments — in web browsers, of course, but JavaScript can also be run server-side, on smartphones, robotically, etc.

Each environment comes with its own object model and syntax to access the global object. Because of that, it can be tough to write JavaScript code that works in multiple environments:

// browser environment
console.log(window);

// node.js environment
console.log(global);

// Service worker environment
console.log(self);
// ...

It is, of course, possible to standardize it across multiple platforms by writing a function that checks for the current environment, but this won’t be needed anymore!

The globalThis property is now the standard way of accessing the global object — across environments — in a consistent manner.

2. ‘Promise.allSettled()’

The Promise.allSettled() method returns a promise that resolves after all of the given promises have either resolved or been rejected, with an array of objects that each describe the outcome of each promise via the status property. This makes it easier to filter them.

const p1 = new Promise((res) => res("🍕"));
const p2 = new Promise((res, rej) => rej("🍍"));
const p3 = new Promise((res) => res("🍺"));
Promise.allSettled([p1, p2, p3]).then(data => console.log(data));
// [
// { status: "fulfilled", value: "🍕" },
// { status: "rejected", value: "🍍" },
// { status: "fulfilled", value: "🍺" },
// ]

3. The Nullish Coalescing Operator

The nullish coalescing operator is a new tool in your toolbox when trying to provide a default value when performing property accesses. It differs from the or operator, symbolized with || between two values, in the manner that it treats nullary values.

Let’s see it in action by comparing the two operators:

const test = {
null: null,
number: 0,
string: '',
boolean: false
};
const undefinedValue = test.dog || "Cat"; // "Cat"
const undefinedValue = test.dog ?? "Cat"; // "Cat"
const nullValue = test.null || "Default"; // "Default"
const nullValue2 = test.null ?? "Default"; // "Default"
const numberValue = test.number || 1; // 1
const numberValue2 = test.number ?? 1; // 0
const stringValue = test.string || "Hello"; // "Hello"
const stringValue2 = test.string ?? "Hello"; // ""
const booleanValue = test.boolean || true; // true
const booleanValue2 = test.boolean ?? true; // false

As you can see, the nullish coalsceing operator only picks the right-hand side value if and only if the expression at the left-hand side of the ?? is either null or undefined.

4. The Optional Chaining Operator

Until now, when looking for a property value that’s deeply nested inside an object or using an API that returns either an object or null/undefined, one often has to proceed this way to check for intermediate values:

// Checking for intermediate nodes:
const deeplyNestedValue = obj && obj.prop1 && obj.prop1.prop2;
// Checking if the node exists in the DOM:
const fooInputEl = document.querySelector('input[name=foo]');
const fooValue = fooInputEl && fooInputEl.value;

The optional chaining operator allows us to handle many of those cases in a handier way. Rewriting the examples above would give:

// Checking for intermediate nodes:
const deeplyNestedValue = obj?.prop1?.prop2;
// Checking if the node exists in the DOM:
const fooValue = document.querySelector('input[name=foo]')?.value;

Good to know

The optional chaining operator is short-circuiting, which means it stops to evaluate the line if the left-hand side of ?. evaluates to null or undefined:

// x is incremented if and only if 'a' is not null or undefined
a?.[++x]

Last thing: The optional chaining operator also works with functions.

func?.(...args) // optional function or method call

5. ‘BigInt’

We already have Number to represent numbers in JavaScript. Problem is, the biggest number is 2⁵³. Above that, it’s not really reliable anymore.

const x = Number.MAX_SAFE_INTEGER; // 9007199254740991
const y = x + 1; // 9007199254740992 • equal to 2^53
const z = x + 2; // 9007199254740992 • well, it's broken

You got it: BigInt is a new primitive to provide a way to represent a number larger than 2 ⁵³. It’s created by appending an n to the end of an integer:

const aBigInteger = 9007199254740993n;
// There is also a constructor:
const evenBigger = BigInt(9007199254740994); // 9007199254740994n
const fromString = BigInt("9007199254740995"); // 9007199254740995n

Good to know

A BigInt mostly has the same behavior as a number, but they can’t be used together in an operation:

let sum = 1n + 2, multiplication = 1n * 2;
// TypeError: Cannot mix BigInt and other types, use explicit conversions

A BigInt can be converted to a Number using the constructor Number(), but in certain cases, you might be losing the precision. For this reason, it’s recommended to only use BigInt when large values are expected in your code.

Number(900719925474099267n); // 900719925474099300 • 🤷‍♂️

6. ‘dynamic import()’

The current form of importing modules import module from './module' is static and only accepts a string literal. It also only works at preruntime as a linking process.

The dynamic import(...) allows developers to be able to dynamically load parts of a JavaScript application at runtime. This comes with multiple advantages the current import doesn’t support:

  • Load user’s language instead of loading them all
  • Lazy loading of routes of your application (improving performance)
  • Can handle failure if the module isn’t found

How does it work?

// Used as a function, import() returns a promise that can be handled the 2 usuals ways:// Using callback
import(
'/module.js')
.then((module) => {
// Do something with the module.
});
// Using async / await
async function () {
let module = await import('/modules.js');
}

Here are the notable differences, compared to the usual import declaration:

  • import() can be used from scripts, not just from modules
  • import() can occur anywhere at any level, and isn’t hoisted
  • import() accepts arbitrary strings (with runtime-determined template strings, as shown here), not just static string literals

7. ‘String.protype.matchAll’

The matchAll() method returns an iterator of all the results matching a string against a regular expression (RegExp) and work this way:

const regexp = RegExp('[a-z]*ball','g');
const str = 'basketball handball pingpong football';
const matches = str.matchAll(regexp);
// Since it is an iterator, you can loop trought results this way:
let match = matches.next();
while (!match.done) {
console.log(match.value);
match = matches.next();
}
// ["basketball", index: 0, input: "basketb...", groups: undefined]
// ["handball", index: 11, input: "basketb...", groups: undefined]
// ["football", index: 29, input: "basketb...", groups: undefined]
// One can also get an array of all results
let results = [...str.matchAll(regexp)];

Good to know

While the match() method doesn’t return capture groups when used with the global /g flag, matchAll() does.

Conclusion

That’s all for this year!

Babel already has plugins for almost all of these features. If you can’t wait to use them in your projects, here are the links:

Thanks for reading!

Better Programming

Advice for programmers.

Sign up for The Best of Better Programming

By Better Programming

A weekly newsletter sent every Friday with the best articles we published that week. Code tutorials, advice, career opportunities, and more! Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Thanks to Zack Shapiro

Thomas Guibert

Written by

Hey! I’m Thomas, a french guy living in Stockholm. Fullstack JavaScript developer, I write about programming and developer’s lifestyle.

Better Programming

Advice for programmers.

Thomas Guibert

Written by

Hey! I’m Thomas, a french guy living in Stockholm. Fullstack JavaScript developer, I write about programming and developer’s lifestyle.

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store