ES2022 Features Overview: Top-Level Await, .at(), and More

2 min

Introduction

With TC39’s annual release process, the JavaScript language continues to evolve every year. ECMAScript 2022 (ES2022) brings a series of new features designed to improve the developer experience and code readability. Let us look at some of the most notable additions.

1. Top-Level await

This is one of the most anticipated features in ES2022. Previously, the await keyword could be used only inside an async function. That was inconvenient when handling asynchronous operations at the top level of a module, and we usually had to wrap asynchronous code in an IIFE (Immediately Invoked Function Expression).

Before 👎:

// data.js
import { fetchData } from './api.js';

let data;
(async () => {
  data = await fetchData();
  // ... 只能在这里使用 data
})();

export { data }; // 导出时 data 还是 undefined

Now (ES2022) 👍:

// data.js
import { fetchData } from './api.js';

const data = await fetchData();

export { data }; // 模块会等待 await 完成后再被其他模块评估

Top-level await greatly simplifies scenarios such as dynamic module loading and dependency initialization, making asynchronous code more intuitive to write.

2. The .at() Array/String Indexing Method

In JavaScript, getting the last element of an array usually requires writing arr[arr.length - 1], which is both verbose and error-prone. ES2022 introduces the .at() method, providing a consistent way to use forward and reverse indexes.

The .at() method accepts an integer. A positive integer returns the element at that index, while a negative integer counts backward from the end.

Before 👎:

const arr = [1, 2, 3, 4, 5];
const lastElement = arr[arr.length - 1]; // 5
const secondToLast = arr[arr.length - 2]; // 4

Now (ES2022) 👍:

const arr = [1, 2, 3, 4, 5];
const lastElement = arr.at(-1); // 5
const secondToLast = arr.at(-2); // 4

// 同样适用于字符串
const str = 'hello';
console.log(str.at(-1)); // 'o'

3. Object.hasOwn(obj, prop)

To check whether an object has an own property rather than an inherited one, we commonly use Object.prototype.hasOwnProperty.call(obj, prop). This is very cumbersome and can fail in certain cases, such as objects created with Object.create(null).

Object.hasOwn() provides a shorter and more reliable static method.

Before 👎:

const obj = { a: 1 };
console.log(Object.prototype.hasOwnProperty.call(obj, 'a')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); // false

Now (ES2022) 👍:

const obj = { a: 1 };
console.log(Object.hasOwn(obj, 'a')); // true
console.log(Object.hasOwn(obj, 'toString')); // false

4. Other Noteworthy Features

  • Error Cause: The Error constructor can now receive a second argument that specifies the “cause” of the error, making it easier to build clearer error chains.
    try {
      // ...
    } catch (err) {
      throw new Error('New error message', { cause: err });
    }
  • RegExp Match Indices (/d flag): When the /d flag is used, regular-expression match results additionally provide the start and end indexes of each capture group.

Conclusion

Although the new features in ES2022 are not revolutionary, they refine JavaScript in important details, solve many long-standing developer pain points, and make code more concise and robust.