---
title: "Exciting Features in ES2022"
url: https://adarsha.dev/blog/es2022
publishedAt: 2022-03-28
summary: "Overview and examples of some exicitng features coming in ES2022."
---

# Exciting Features in ES2022

> Overview and examples of some exicitng features coming in ES2022.

Source: https://adarsha.dev/blog/es2022

In this article we will look at some cool features that are coming in ECMAScript 2022. Since its inception in 1997, ES2022 will be Javascript's 13th edition. At the time of writing this article all the features have already [reached Stage 4](https://github.com/tc39/proposals/blob/main/finished-proposals.md) and are expected to be released by July, 2022.

## 1. Class Fields

### Private Fields and Methods

Previously there wasn't any mechanism to setup private class fields in Javascript.

```js
class Post {
  title = "Default Title"; // public
  _date = Date.now(); // private

  print() {
    console.log(this.title, this.date);
  }
}

const post = new Post();
post.title = "New Post"; // public field accessed from outsite

post._date = "2022/10/20"; // even though we have access private field outsite of class

post.print();
```

Even though `_date` field is marked as private, `_` underscore is just naming convention for private field, it's not there in language specification so can be accessed from outside and doesn't shows any error. So there wasn't any Encapsulation in fields and methods in Js specs.

Now in ES2022 we have private class fields and methos. For that we have to prefix our methods and fields with pound `#` sign. Also, whenever we try to access private field we have to prefix `#`.

```js
class Post {
  title = "Default Title";
  #date = Date.now(); // private field from ES2022

  print() {
    console.log(this.title, this.#date); // ✅ can access private field within class
  }

  #getTitle() {
    return this.title;
  }
}

const post = new Post();
post.title = "New Post";

post.#date = "2022/10/20"; // ❌ Uncaught SyntaxError: Private field '#date' must be declared in an enclosing class
post.getTitle(); // ❌ Uncaught SyntaxError: Private field '#print' must be declared in an enclosing class
post.print();
```

### Static Methods and Fields

The static members of a class are accessed using the class name and dot notation, without creating an object.

Previously,

```js
class Cirlce {
  getArea() {}
}

Cricle.PI = 3.14; // define sttaic fields
```

But now with introduction to `static` keywordwe can directly define it inside class.

```js
class Circle {
  static PI = 3.14;

  static getArea(radius) {
    return this.PI * Math.pow(radius, 2);
  }
}

console.log(Circle.getArea(3));
```

## 2. Top-level `await`

Previously we need we can't declare `await` keyword outside `async` function.

When we fetch the data from api using `async await`, we return promises and use `then()` to use the data.

```js
async function getPost() {
  const data = await fetch("https://jsonplaceholder.typicode.com/posts/1");
  const postJson = await data.json();
  return postJson;
}

getPost().then((post) => console.log(post));
```

But now we can directly use await keyword without wrapping it inside async function. With top-level `await` it will treat the whole module as `async` function.

```js
const post = await fetch("https://jsonplaceholder.typicode.com/posts/1");
console.log(posts);
```

There we other exciting usecases for it [Check tc39 proposal](https://github.com/tc39/proposal-top-level-await#use-cases).

## 3. Relative indexing using `.at()` method

Till noew we can only access the elements in array using positive index, so have calculate the length of array and calculate the value accordingly. After ES2022, we can easily access the elements using positive or negative index using `at()` method.

```js
const arr = Array(100)
  .fill()
  .map(() => Math.random());

arr[arr.length - 1]; // prev, 100

arr.at(-1); // last num i.e 100
arr.at(-2); // second last i.e 99
```

## 4. Accessible `Object.hasOwn()` method

This method is used to confirm wether the certian property exists in object itself or nested prototypical chain of that object. Previously we used to have `Object.hasOwnProperty()` to do the same thing. `hasOwnProperty` tries to check if certain property exists inside object itself, if that property exists inside its prototype then it will return `false`. Issue with this method is that, JavaScript does not protect the property name hasOwnProperty; an object that has a property with this name may return incorrect results:

```js
const user = {
  name: "John",

  // override hasOwnProperty() method in obj
  hasOwnProperty() {
    return false;
  },
};

user.hasOwnProperty("name"); // always return false since we override it to return false
```

Instead of calling `hasOwnProperty()` on object prototypical chain (`user` in our case), we pass the object and property we want to check inside the `hasOwn()` method shipped in ES2022 `Object` class itself.

```js
const user = {
  name: "John",
  age: 20,
};

Object.hasOwn(user, "name"); // true
```

## 5. Error .cause

Most of the time error are wrapped with meaningful message about case of error, but original contextual information of error might get lost. Using error `cause` we can attach the original error to a wrapping error. The options parameter is added to `Error()` constructor with `cause` property and a `cause` field is used for retrieving the original error.

```js
const getPost = async (postId) => {
  try {
    const data = await fetch(
      `https://jsonplaceholder.typicode.com/posts/${postId}`,
    );
    const postJson = await data.json();
    return postJson;
  } catch (error) {
    throw new Error(`Loading data for post with id ${postId} failed.`, {
      cause: error,
    });
  }
};
try {
  const post = await getPost(4352);
  // do something
} catch (error) {
  console.log(error); // Error: Loading data for post with id 4352 failed.
  console.log(error.cause); // TypeError: Failed to fetch
}
```

## 6. RegExp Match Indices

RegExp Match Indices provide additional information about the start and end indices of captured substrings. While calling the `RegExp.exec` or `String.matchAll()` methods, we provide additional `/d` flag to regular expression, the start and end index are available in the `indices` array property of the result.

In the below example we find all the indices of the switch reserved keyword present in out code.

```js
const statement = "const switch = 0";
const regex = /(switch)/dg;

const matches = [...statement.matchAll(regex)];

console.log(matches);

/**
 * Result :
[
  "switch",
  "switch",
  groups: undefined,
  index: 6,
  indices: [
    [6, 12],
    [6, 12],
    groups: undefined
  ]
  input: "const switch = 0",
  length: 2,
]
 */
```

Most of the above features are already available in modern browsers, and Node.js environment, but for production use we might need to polyfill for target environment.

## References

- [TC39 Finished Proposals](https://github.com/tc39/proposals/blob/main/finished-proposals.md)
