This chapter lists what’s new in ES2016–ES2022 in reverse chronological order. It starts after ES2015 (ES6) because that release has too many features to list here.
ES2022 will probably become a standard in June 2022. The following proposals have reached stage 4 and are scheduled to be part of that standard:
New members of classes:
Private slot checks (“ergonomic brand checks for private fields”): The following expression checks if obj
has a private slot #privateSlot
:
in obj #privateSlot
Top-level await
in modules: We can now use await
at the top levels of modules and don’t have to enter async functions or methods anymore.
error.cause
: Error
and its subclasses now let us specify which error caused the current one:
new Error('Something went wrong', {cause: otherError})
Method .at()
of indexable values lets us read an element at a given index (like the bracket operator []
) and supports negative indices (unlike the bracket operator).
> ['a', 'b', 'c'].at(0)'a'
> ['a', 'b', 'c'].at(-1)'c'
The following “indexable” types have method .at()
:
string
Array
Uint8Array
etc.RegExp match indices: If we add a flag to a regular expression, using it produces match objects that record the start and end index of each group capture.
Object.hasOwn(obj, propKey)
provides a safe way to check if an object obj
has an own property with the key propKey
. In contrast to Object.prototype.hasOwnProperty
, it works with all objects.
More features may still be added to ES2022
If that happens, this book will be updated accordingly.
The following features were added in ECMAScript 2021:
String.prototype.replaceAll()
lets us replace all matches of a regular expression or a string (.replace()
only replaces the first occurrence of a string):
> 'abbbaab'.replaceAll('b', 'x')'axxxaax'
Promise.any()
and AggregateError
: Promise.any()
returns a Promise that is fulfilled as soon as the first Promise in an iterable of Promises is fulfilled. If there are only rejections, they are put into an AggregateError
which becomes the rejection value.
We use Promise.any()
when we are only interested in the first fulfilled Promise among several.
||= b
a &&= b
a ??= b a
Underscores (_
) as separators in:
123_456.789_012
6_000_000_000_000_000_000_000_000n
WeakRefs: This feature is beyond the scope of this book. For more information on it, see its proposal.
The following features were added in ECMAScript 2020:
New module features:
Dynamic imports via import()
: The normal import
statement is static: We can only use it at the top levels of modules and its module specifier is a fixed string. import()
changes that. It can be used anywhere (including conditional statements) and we can compute its argument.
import.meta
contains metadata for the current module. Its first widely supported property is import.meta.url
which contains a string with the URL of the current module’s file.
Namespace re-exporting: The following expression imports all exports of module 'mod'
in a namespace object ns
and exports that object.
export * as ns from 'mod';
Optional chaining for property accesses and method calls. One example of optional chaining is:
.?prop value
This expression evaluates to undefined
if value
is either undefined
or null
. Otherwise, it evaluates to value.prop
. This feature is especially useful in chains of property reads when some of the properties may be missing.
Nullish coalescing operator (??
):
?? defaultValue value
This expression is defaultValue
if value
is either undefined
or null
and value
otherwise. This operator lets us use a default value whenever something is missing.
Previously the Logical Or operator (||
) was used in this case but it has downsides here because it returns the default value whenever the left-hand side is falsy (which isn’t always correct).
Bigints – arbitrary-precision integers: Bigints are a new primitive type. It supports integer numbers that can be arbitrarily large (storage for them grows as necessary).
String.prototype.matchAll()
: This method throws if flag /g
isn’t set and returns an iterable with all match objects for a given string.
Promise.allSettled()
receives an iterable of Promises. It returns a Promise that is fulfilled once all the input Promises are settled. The fulfillment value is an Array with one object per input Promise – either one of:
{ status: 'fulfilled', value: «fulfillment value» }
{ status: 'rejected', reason: «rejection value» }
globalThis
provides a way to access the global object that works both on browsers and server-side platforms such as Node.js and Deno.
for-in
mechanics: This feature is beyond the scope of this book. For more information on it, see its proposal.
The following features were added in ECMAScript 2019:
Array method .flatMap()
works like .map()
but lets the callback return Arrays of zero or more values instead of single values. The returned Arrays are then concatenated and become the result of .flatMap()
. Use cases include:
Array method .flat()
converts nested Arrays into flat Arrays. Optionally, we can tell it at which depth of nesting it should stop flattening.
Object.fromEntries()
creates an object from an iterable over entries. Each entry is a two-element Array with a property key and a property value.
String methods: .trimStart()
and .trimEnd()
work like .trim()
but remove whitespace only at the start or only at the end of a string.
Optional catch
binding: We can now omit the parameter of a catch
clause if we don’t use it.
Symbol.prototype.description
is a getter for reading the description of a symbol. Previously, the description was included in the result of .toString()
but couldn’t be accessed individually.
These new ES2019 features are beyond the scope of this book:
JSON.stringify()
: See 2ality blog post.Function.prototype.toString()
revision: See 2ality blog post.The following features were added in ECMAScript 2018:
Asynchronous iteration is the asynchronous version of synchronous iteration. It is based on Promises:
await
before we can access an item.for-of
loops. With asynchronous iterables, we use for-await-of
loops.Spreading into object literals: By using spreading (...
) inside an object literal, we can copy the properties of another object into the current one. One use case is to create a shallow copy of an object obj
:
const shallowCopy = {...obj};
Rest properties (destructuring): When object-destructuring a value, we can now use rest syntax (...
) to get all previously unmentioned properties in an object.
const {a, ...remaining} = {a: 1, b: 2, c: 3};
.deepEqual(remaining, {b: 2, c: 3}); assert
Promise.prototype.finally()
is related to the finally
clause of a try-catch-finally statement – similarly to how the Promise method .then()
is related to the try
clause and .catch()
is related to the catch
clause.
On other words: The callback of .finally()
is executed regardless of whether a Promise is fulfilled or rejected.
New Regular expression features:
RegExp
named capture groups: In addition to accessing groups by number, we can now name them and access them by name:
const matchObj = '---756---'.match(/(?<digits>[0-9]+)/)
.equal(matchObj.groups.digits, '756'); assert
RegExp
lookbehind assertions complement lookahead assertions:
(?<=X)
matches if the current location is preceded by 'X'
.(?<!X)
matches if the current location is not preceded by '(?<!X)'
.s
(dotAll
) flag for regular expressions. If this flag is active, the dot matches line terminators (by default, it doesn’t).
RegExp
Unicode property escapes give us more power when matching sets of Unicode code points – for example:
> /^\p{Lowercase_Letter}+$/u.test('aüπ')true
> /^\p{White_Space}+$/u.test('\n \t')true
> /^\p{Script=Greek}+$/u.test('ΩΔΨ')true
Template literal revision allows text with backslashes in tagged templates that is illegal in string literals – for example:
windowsPath`C:\uuu\xxx\111`
latex`\unicode`
The following features were added in ECMAScript 2017:
Async functions (async/await
) let us use synchronous-looking syntax to write asynchronous code.
Object.values()
returns an Array with the values of all enumerable string-keyed properties of a given object.
Object.entries()
returns an Array with the key-value pairs of all enumerable string-keyed properties of a given object. Each pair is encoded as a two-element Array.
String padding: The string methods .padStart()
and .padEnd()
insert padding text until the receivers are long enough:
> '7'.padStart(3, '0')'007'
> 'yes'.padEnd(6, '!')'yes!!!'
Trailing commas in function parameter lists and calls: Trailing commas have been allowed in Arrays literals since ES3 and in Object literals since ES5. They are now also allowed in function calls and method calls.
The following two features are beyond the scope of this book:
Object.getOwnPropertyDescriptors()
(see “Deep JavaScript”)The following features were added in ECMAScript 2016:
Array.prototype.includes()
checks if an Array contains a given value.
> 4 ** 216
ECMAScript feature lists were taken from the TC39 page on finished proposals.