Published on

What's New in JavaScript ES2021?

Authors

This post is a collection of all the latest features added to JavaScript as part of the ES2021 Spec.

ES2021

String.prototype.replaceAll - proposal📘

This new method provides a more straight-forward way to replace all occurences of a matching substring in a string without using regex or array methods.

The most common approach for doing this is using a regex expression with the replace method:

const animals = 'dinosaurs+dogs+cats+alligators';
const withSpaces = animals.replace(/\+/g, ' ');

And the regex-free aproach uses split & join:

const animals = 'dinosaurs+dogs+cats+alligators';
const withSpaces = animals.split('+').join(' ');

The new approach is to use replaceAll. No regex, no unnecessary converting back and forth from arrays.

const animals = 'dinosaurs+dogs+cats+alligators';
const withSpaces = animals.replaceAll('+', ' ');

Promise.any proposal📘

Promise.any accepts an iterable of promises and returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an AggregateError holding the rejection reasons if all of the given promises are rejected. (If something more fundamental goes wrong, e.g. iterating over the iterable results in an exception, Promise.any returns a rejected promise with that exception.)

Example

const promiseWithError = new Promise((resolve, reject) => {
reject('Always fails');
});
const promiseSlow = new Promise((resolve, reject) => {
setTimeout(resolve, 600, 'Done eventually.');
});
const promiseMedium = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'Done pretty fast.');
});
const promiseFast = new Promise((resolve, reject) => {
setTimeout(resolve, 10, 'Done first!');
});
Promise.any([
promiseWithError,
promiseSlow,
promiseMedium,
promiseFast,
]).then((value) => {
console.log(value);
// promiseFast fulfils first
});
// output: "Done first!"

WeakRefs proposal📘

The primary use case for weak references is to create caches or mappings to large objects.

According to the proposal: "it's best if WeakRef objects and FinalizationRegistry objects are used as a way to avoid excess memory usage, or as a backstop against certain bugs, rather than as a normal way to clean up external resources or observe what's allocated."

In other words, don't use these new features unless you are really sure you know what you're doing.

Let's look at an example:

const callback = () => {
const hugeObject = new WeakRef({
name: 'A Huge Object v2.0',
});
console.log(hugeObject.deref().name);
};
const promise1 = new Promise((resolve) => {
setTimeout(() => {
callback(); // Will log "A Huge Object v2.0"
resolve();
}, 2000);
});
const promise2 = await new Promise((resolve) => {
setTimeout(() => {
callback(); // No guarantee "A Huge Object v2.0" will be logged
resolve();
}, 50000);
});
Promise.all([promise1, promise2]);

Logical Assignment Operators proposal📘

This new feature combines the logical operations(&&, || & ??) with assignment (=) into three new operators: &&=, ||= & ??=.

So now instead of writing this:

let x = 0;
let y = 2;
if (x) {
x = y;
}
console.log(x); // prints 2

Or this:

let x = 0;
let y = 2;
x && (x = y);
console.log(x); // prints 2

We can just write:

let x = 0;
var y = 2;
x &&= y;
console.log(x); // prints 2
let a;
let b = a ?? 4;
console.log(b); // 4
// This can be simplified to this
let c;
let d = 4;
c ??= d;
console.log(c); // 4

Numeric separators proposal📘

One of the simplest additions to the ES2021 spec is underscores (_) as a numeric separator.

The primary purpose of this is to make code more readble. What is "10000000000", one billion, or ten billion? Using the _ to break up values makes them much easier to read.

const trillion = 1_000_000_000_000; // Instantly readable as opposed to 1000000000000
const tenBillion = 10_000_000_000;
const twentyDollarsInCents = 20_00; // It's obvious that 2000 here refers to 20 dollars and 0 cents