Pascal Akunne A JavaScript developer focused on building human-centric products with HTML, CSS, React, Node.js, and MongoDB

What to expect from ES2022

5 min read 1423

ES2022 What To Expect

JavaScript is the most commonly used programming language, according to Stack Overflow’s 2020 Developer Survey, and it is continually evolving. In fact, new ECMAScript specifications have been released every year since 2015. At the time of this writing, several new feature proposals have passed the fourth proposal stage and are anticipated to be included in ES2022, JavaScript’s 13th version.

In this article, we’ll take a look at the eight feature proposals that are expected to be released in mid-2022:

Delaying the execution of modules with top-level await

ES2022 will enable developers to use await outside of the asynchronous (async) function scope, making it easier to use at the module level.

Here’s an example of how await is used prior to ES2022:

import users from './users'

const getUsers = async() => {
  let users = await users()
  return users
}

Here’s the same example, showing how await will be used under ES2022:

let users = await import './users'

The top-level await feature delays the execution of current and parent modules until the imported module is loaded. Using this feature, modules can use runtime values to determine dependencies. Top-level await can also be used as a fallback for dependencies.

let users;
try {
  users = await import('https://example1.com/users');
} 
catch {
  users = await import('https://example2.com/users');
}

RegExp match indices with the d flag

Regular expression matches are patterns that are used to find certain character combinations in strings. In a result, RegExp.exec and String.matchAll return a list of matches.

const names = 'Names: John, Frank, Johnson, Kelly'
const regex = /(John)/g;

// .exec
// RegExp(regex).exec(names);
// [
//   'John',
//   index: 7,
//   input: 'Names: John, Frank, Johnson, Kelly',
//   groups: undefined
// ]

// matchAll
const matches = [...names.matchAll(regex)];
matches[0];
// [
//   'John',
//   'John',
//   index: 7,
//   input: 'Names: John, Frank, Johnson, Kelly',
//   groups: undefined
// ]

RegExp.exec delivers results individually, while String.matchAll returns an iterator that may be used to iterate over all matches.

ES2022 will allow developers to use the d flag to specify the starting and ending indices of matches in a RegExp result. Here’s an example:

const names = 'Names: John, Frank, Johnson, Kelly'
const regex = /(John)/gd;
const matches = [...names.matchAll(regex)];
matches[0];
// [
// "John",
// "John",
// groups: undefined
// index: 7
// indices:[]
//  [7, 11],
//  [7, 11]
// ]
// groups: undefined

class field declarations

Defining and enforcing private fields with the # prefix

Prior to ES2022, class fields are simply defined in the constructor. Fields prefixed by an underscore (_) are traditionally inaccessible outside of the class since they are considered private. Take a look at the following sample code:

We made a custom demo for .
No really. Click here to check it out.

class User {

  constructor(){

      // public field
      this.name = 'kodex'

      // private field
      this._password = '1234';
  }
}

const user = new User();
console.log(user.name);
// name - public fields are accessible outside the classes

user._password = 'qwert';
console.log(user._password);
// password - no error thrown, we can access it from outside the class

In this example, the private _password property is accessed and modified outside of the class.

ES2022 will enable developers to define and enforce a private field by simply inserting a # prefix before the field name. ES2022 also removes the need for public or private fields to be defined in the constructor().

Consider the following example:

class User {

  // public field
  name = 'kodex'

  // private field
  #password = '1234';
}

const  user = new User()

console.log(user.#password);
user.#password = 'qwert';
// error - Private field '#password' must be declared in an enclosing class

In this code, an attempt to access the private field outside of the class results in an error.

Restricting private field methods and accessors with the # prefix

ES2022 also enables developers to use the # prefix with private methods and accessors (“getters” and “setters”) to restrict a class’s methods and variables. This keeps the methods and accessors strictly internal and prevents them from being accessed outside of the class. Here’s an example:

class User {

  // public field
  name = 'kodex'

  // private field
  #password = '1234';

  #getPwd(){
    return this.#password
  }

  set #setPwd(data){
    this.#password = data
  }
}

const user = new User()

// Error - Private field '#getPwd' must be declared in an enclosing class
console.log(user.#getPwd);

// Error - Private field '#setPwd' must be declared in an enclosing class
user.#setPwd = 'qwert';```

Specifying static fields and private static methods with the static keyword

Static class fields and methods are only accessible in the class prototype, rather than in every instance of the class. Prior to ES2022, a class‘s static fields may be specified as follows:

class Animal {}
Animal.cow = "mammal"

Under ES2022, the static keyword may be used to specify a class‘s static fields and private static methods. Here’s an example:

class Animal {
static cow = "mammal"
}

Ergonomic brand checks for private fields using the in keyword

An attempt to access a private field outside of a class currently results in an exception being thrown, rather than undefined being returned. We could use try/catch inside of a class to determine if a private field exists. However, the issue with this method is that it can be difficult to determine the source of an exception.

ES2022 will provide developers with the in keyword that can be used to produce a Boolean indicating the presence of a private field. This simple solution does not require a try/catch method or exceptions:

class Person{
  #name = 'Kelly';
  get #getName(){
    return #name;
  }
  set #setName(){
    #name = 'Anna';
  }
  static hasTitle(obj){
    return #name in obj;
  }
}

Negative indexing with the .at() method

The .at() method provides easy access to any index of an array or string, either positive or negative. Here’s an example:

array= [1, 2, 3, 4, 5]
console.log(array[array.length-1]); // 5
console.log(array.at(-1)); // 5

ES2022 will enable developers to add the .at() method to an array and use a negative integer value to count backward from the end of the array.

More accessible Object.prototype.hasOwnProperty with the Object.hasOwn() method

By convention, the hasOwnProperty can’t be used outside of the prototype itself. An object could have a property called hasOwnProperty that differs from the Object.prototype.hasOwnProperty. Here’s an example:

const employee = {
  hasOwnProperty:()=> {
    return false
  }
}
obj.hasOwnProperty('prop'); // false

ES2022 will enable developers to address this issue, by using the Object.hasOwn() method. This method takes the object as the first parameter and the property we wish to verify as the second parameter:

const employee = {
name: 'Grace',
age: 18
}
Object.hasOwn(employee, 'name'); // true
Object.hasOwn(employee, 'position'); // false

Initialization during class definition evaluation with static{} blocks

Traditionally, statements like try/catch are evaluated outside of the class body during initialization.

class UserStatus{
    status = false;
    get getStatus(){
        if(!this.#status){
            throw new Error('User is not active');
        } 
        return this.#status
    }
}

// evaluate outside the class body
try {
    const state = UserStatus.getStatus;
    UserStatus.status = state
} catch {
    UserStatus.status = false
}

ES2022 will permit developers to use static{} blocks to evaluate statements within the scope of a class declaration. This is useful in instances in which there is a need to set up multiple static fields. static{} blocks permit access to a class’s private states (methods and fields) and allow information to be shared between classes or functions declared in the same scope.

let initState;

class UserStatus{
    #status = false;

    get getStatus(){
        if(!this.#status){
            throw new Error('User is not active');
        } 
        return this.#status
    }
    static {
        initState = () => {
            this.#status = this.getStatus;
        }
    }
}

initState();

Chaining errors with the cause property

Errors are traditionally identified and addressed during runtime using contextual information such as error messages and error instance properties. If an error occurs in a deeply nested function, its cause can be difficult to determine in the absence of a proper exception design pattern.

function processData(arrayData) {
  return arrayData.map(data => {
      try {
        const json = JSON.parse(data);
        return json;
      } catch (error) {
        // throw random error
      }
    });

In ES2022, the cause property is added to the Error() constructor as an extra parameter, allowing errors to be chained without the need for unnecessary formalities on wrapping the errors in conditions.

function processData(arrayData) {
  return arrayData.map(data => {
      try {
        const json = JSON.parse(data);
        return json;
      } catch (err) {
        throw new Error(
          `Data processing failed`,
          {cause: err}
        );
      }
    });
}

Conclusion

It is essential that developers stay current with the latest language specifications. In this article, we looked at eight new features that will be available with JavaScript’s ES2022 specification. JavaScript is continually evolving, with new features being added each year. We’re excited to see what new features are in store for ES2023!

: Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

.
Pascal Akunne A JavaScript developer focused on building human-centric products with HTML, CSS, React, Node.js, and MongoDB

Leave a Reply