New JavaScript Features ECMAScript 2022 (with examples)
Tags: javascript, webdev, programming, typescript
Published: 2022-06-27 14:42:57

**ECMAScript 2022** is the version of ECMAScript corresponding to this year. There are some new features that have been incorporated and could be used in our javascript projects. Also if you want to see the **ES2021** I had created the next blog post for that [New JavaScript Features ECMAScript 2021 (with examples)](https://dev.to/brayanarrieta/new-javascript-features-ecmascript-2021-with-examples-3hfm)

The new **ECMAScript** features for this year are:

- Top-level await
- Private instance fields, methods, and accessors
- Static class fields and methods
- Static class initialization blocks
- Error: .cause
- Array, String, and TypedArray: .at() Method
- Object: .hasOwn()
- RegExp: match .indices ('d' flag)

## Top-level await

Until this point, we could only use await in the scope of `async functions`. This was fine until it wasn't, like when we hit the top level of our module and could not use the await keyword. Now the `await` can be used at the top level of a module and can be super handy when initializing imports and creating fallbacks.

### Example

#### The old behavior

When the async/await feature was first introduced, attempting to use an await outside of an async function resulted in a SyntaxError. Many developers utilized as an alternative **IIFE** (Immediately Invoked Function Expression) as a way to get access to the feature.

```javascript
await Promise.resolve(console.log('Hello World'));
// Output: SyntaxError: await is only valid in async function

// Alternative to fix the problem
(async function() {
  await Promise.resolve(console.log('Hello World'));
  // Output: Hello World
}());
```

#### The new behavior
With top-level await, we don't need to use more **life hacks**.

```javascript
await Promise.resolve(console.log('Hello World'));
// → Hello World
```

### Use cases

#### Dynamic dependency pathing

```javascript
const strings = await import(`/i18n/${navigator.language}`);
```

This allows for Modules to use runtime values in order to determine dependencies. This is useful for things like development/production splits, internationalization, environment splits, etc.

#### Resource initialization

```
const connection = await dbConnector();
```

This allows Modules to represent resources and also to produce errors in cases where the Module will never be able to be used.

#### Dependency fallbacks

```javascript
let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}
```

## Private instance fields, methods, and accessors

Previously when was needed to declare a private method or field needs to be added an underscore at the beginning of the method name (based on convention), however, that does not guarantee that the method will be private.

With **ES2022** was added as new features as private instance fields, methods, and accessors. We need to add just **#** at the beginning of the method name and in that way will be declared as private.

### Private class fields

#### Example
```javascript
class Test {
  #firstName = 'test-name';
}

const test = new Test();
test.firstName

// Output: undefined
``` 

### Private class methods

#### Example
```javascript
class Test {

  #addTestRunner(testRunner){
    this.testRunner = testRunner
  }
}

const test = new Test();
test.addTestRunner({name: 'test'});

// Output: TypeError: test.addTestRunner is not a function
``` 

### Private accessors (getters and setters)
Previously when was needed to declare a getter or setter can be accessed by means of the instance created, with ES2022 was added as a new feature the private accessors.

#### Example
```javascript
class Test {

  get #name(){
    return 'test-name';
  }
}

const test = new Test();
test.name

// Output: undefined
``` 

## Static class fields and methods

Static class fields and methods are not used on instances of a class. Instead, can be called on the class itself and is declared using the `static` keyword.

Static methods are often utility functions, and helpers, whereas static properties are useful for caches, fixed-configuration, or any other data we don’t need to be replicated across instances.

### Examples

#### Static class fields

```javascript
class Test {
  static firstName = 'test-static-name';
}

Test.firstName

// Output: test-static-name
``` 

#### Static class methods

```javascript
class Test {
  static greeting(){
    console.log('Hello this is a greeting from a static method');
  }
}

Test.greeting();

// Output: Hello this is a greeting from a static method
```

**Note**: We are using in these examples as static public fields and methods, however, we can create also static private fields and methods.

## Static class initialization blocks
This new feature provides a mechanism for additional static initialization during class definition evaluation.

### Example

```javascript
class Test {
  static numbers = [1,2,3,4,5,6];
  static evenNumbers = [];
  static oddNumbers = [];
  
  // static class initialization block
  static {
   this.numbers.forEach((number) => {
     if(!(number % 2) ) {
       this.evenNumbers.push(number);
     } else {
        this.oddNumbers.push(number);
     }
   });
  }
}

Test.evenNumbers;
// Output: [2, 4, 6]

Test.oddNumbers;
// Output: [1, 3, 5]
```

## Error: .cause

**Error** and its **subclasses** now let us specify the reason behind the error. Sometimes, we catch errors that are thrown during more deeply nested function calls and would like to attach more information to them. 

With the **Error cause**, we can add more intrinsic information for our errors. To use this new feature, we should specify the error options as a second parameter, and with the **cause** key we can pass the error that we want to chain.

### Example
```
const getUsers = async(array)=> {
  try {
    const users =  await fetch('https://myapi/myusersfake');
    return users;
  } catch (error) {
    console.log('enter')
    throw new Error('Something when wrong, please try again later', { cause: error })
  }
}

try{
  const users = await getUsers();
} catch(error) {
  console.log(error); // Error: The array need a minimum of two elements
  console.log(error.cause); // TypeError: Failed to fetch
}

```

## Array, String, and TypedArray: .at() Method

Until this point, programmers have asked for the ability to do **negative indexing** of JS Arrays, as you can do with other programming languages. That is, asking for the ability to write **arr[-1]** instead of **arr[arr.length-1]**, where negative numbers count backward from the last element.

This year with **ECMAScript 2022** we have a big change with a new method that helps programmers with the **negative indexing**, the **.at()** method that is supported by **Array**, **String**, or **TypedArray**.

### Example

Access the latest element of the Array and String

#### The old behavior

```javascript
const fruitsArray = ['banana', 'apple', 'orange', 'kiwi'];
console.log(fruitsArray[fruitsArray.length -1])
// Output: kiwi

const fruit = 'kiwi';
console.log(fruit[fruit.length -1])
// Output: i
```

#### The new behavior

```javascript
const fruitsArray = ['banana', 'apple', 'orange', 'kiwi'];
console.log(fruitsArray.at(-1))
// Output: kiwi

const fruit = 'kiwi';
console.log(fruit.at(-1))
// Output: i
```
**Note**: The **.at()** also accepts positive numbers, so it can be used as another way when indexing is required.

## Object: .hasOwn()

Today, it is very common (especially in library code) to write code like

```javascript
let hasOwnProperty = Object.prototype.hasOwnProperty

if (hasOwnProperty.call(object, "foo")) {
  console.log("has property foo")
}
```

This new feature simplifies that code to

```javascript
if (Object.hasOwn(object, "foo")) {
  console.log("has property foo")
}
```

## RegExp: match .indices ('d' flag)

The new **/d flag** feature provides some additional information about the start and indices position end of each match in the input string.

### Example

#### Without the /d flag

```javascript
const regexExample = /greeting(\d)/g;
const exampleString = 'greeting1greeting2';
const result = [...exampleString.matchAll(regexExample)];
console.log(result[0]);
```

**Output**

<center>
![Without d flag output](https://cdn.hashnode.com/res/hashnode/image/upload/v1647371628844/0B-G-CV2N.png)
</center>

#### With the /d flag

```javascript
const regexExample2022 = /greeting(\d)/dg;
const exampleString = 'greeting1greeting2';
const result = [...exampleString.matchAll(regexExample2022)];
console.log(result[0]);
```

**Output**
<center>
![With d flag output](https://cdn.hashnode.com/res/hashnode/image/upload/v1647371583021/uec5fG6Qf.png)
</center>
With the **/d flag** we have an array with the indices of the different elements that match the regex.

## Conclusion
JavaScript is an awesome programing language. Every year there is a new awesome feature that can be used in our projects. In this post, we’ve reviewed the **ES2022** features. We expect surprises the next year with a new version **ES2023**. Also if you want to see the **ES2021** I had created the next blog post for that [New JavaScript Features ECMAScript 2021 (with examples)](https://dev.to/brayanarrieta/new-javascript-features-ecmascript-2021-with-examples-3hfm)

Let me know in your comments recommendations or something else that can be added, I will update the post based on that thanks! 👍

<a href="https://www.buymeacoffee.com/brayanarrieta"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=brayanarrieta&button_colour=5F7FFF&font_colour=ffffff&font_family=Cookie&outline_colour=000000&coffee_colour=FFDD00"></a>


## References
- [ECMAScript proposals](https://github.com/tc39/proposals/blob/main/finished-proposals.md)
- [ECMAScript® 2022 Language Specification](https://tc39.es/ecma262/)