Skip to content
Theme:

What's new in ECMAScript 2022

The ECMAScript 2022 Language Specification candidate is now available. Even though the final version will be approved in June, the list of new features coming to the language this year is already defined. Similarly, how I did it in 2016, 2017, 2018, 2019, 2020 and 2021, let’s look at what’s coming to ECMAScript specification in 2022.

Class fields (public, static, private) and private class methods by Daniel Ehrenberg and Kevin Gibbons

This proposal adds long-awaited class fields (public, static, private) and private methods to the ECMAScript classes. This feature will simplify or sometimes eliminate the need for a constructor to create instance properties. In addition, static fields eradicate the need for static getters or external assignments to the instances. Finally, private fields and private methods allow us to create genuinely protected data slots that are accessible only in the body of a class.

class MyClass {
  // no need for a constructor
  // constructor() {
  //   this.publicField = 1;
  // }
  publicField = 1;

  // no need for external assignment or a static getter
  // static get staticField() {
  //   return 2;
  // }
  static staticField = 2;

  #privateField = 3;

  #privateMethod() {
    return 4;
  }
}

const instance = new MyClass();

console.log(instance.publicField); // 1
console.log(MyClass.staticField); // 2
// console.log(instance.#privateField); // SyntaxError: Private field '#privateField' must be declared in an enclosing class
// console.log(instance.#privateMethod()); // SyntaxError: Private field '#privateMethod' must be declared in an enclosing class

RegExp Match Indices by Ron Buckton

This proposal gives us more information about captured groups start and end indices. Additional output about indices on RegEx object can be enabled using the d flag (the i flag is reserved for case folding, so we so ended up with d due to its presence in the word indices 🤷‍♂️).

const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/d;
//                                                            👆
const string = "2022-04-04";
const result = pattern.exec(string);

console.log(result.indices);
// [
//   [ 0, 10 ],
//   [ 0, 4 ],
//   [ 5, 7 ],
//   [ 8, 10 ],
//   groups: [Object: null prototype] {
//     year: [ 0, 4 ],
//     month: [ 5, 7 ],
//     day: [ 8, 10 ]
//   }
// ]

Top-level await by Myles Borins, Yulia Startsev, Daniel Ehrenberg, Guy Bedford, Ms2ger and others

This proposal enables top-level await without wrapping it in an async function.

// Quick reminder, you may not need node-fetch anymore
// node --experimental-fetch index.mjs

// Look ma, no async function 😱
await fetch("https://api.github.com/users/pawelgrzybek")
  .then((response) => response.json())
  .then((responseJson) => console.log(responseJson.blog));

// https://pawelgrzybek.com

Ergonomic brand checks for Private Fields by Jordan Harband

With the introduction of private fields in ECMAScript classes, we need a simple solution to check the presence of a private field on an object. This propoal does precisely that.

class MyClass {
  #hello = "hi";

  static checkHi(object) {
    return #hello in object;
  }
}

console.log(MyClass.checkHi(new MyClass()));
// true

Accessible Object.prototype.hasOwnProperty() by Tierney Cyren and Jamie Kyle

This proposal adds an Object.hasOwn(object, property) method with the same behaviour as calling hasOwnProperty.call(object, property). Calling hasOwnProperty() on an object is not 100% safe because you can’t be assured that property has not been reassigned if you don’t own the object. Calling Object.hasOwn() is much safer.

const dude = {
  name: "Pawel",
  hasOwnProperty() {
    return false;
  },
};

// 👎 Uuuups, I can clearly see that the 'name' property is there
console.log(dude.hasOwnProperty("name"));
// false

// 👍 Thats safer
console.log(Object.hasOwn(dude, "name"));
// true

The .at() method on all the built-in indexables

This proposal allows us to do negative indexing on arrays, strings and typed arrays, similarly to how we can do it in other languages like Python. Currently, the only most popular method to access the last element of an arr is arr[arr.length - 1]. With this new proposal, we can do better.

const fruits = ["pawel", "dan", "pedro"];

console.log(fruits.at(-1));
// pedro

Class static initialization blocks

This proposal gives us an additional way to perform static initialization during class evaluation. It helps to evaluate statements during initialization and avoid declaring this logic outside of the class.

// This is the old way, pre 2022

class MyClass {
  static runtime;
}

try {
  MyClass.runtime = `Node ${process.version.replace("v", "")}`;
} catch {
  MyClass.runtime = "It is probably Deno";
}

console.log(MyClass.runtime);
// In ECMAScript 2022 we can do it like that

class MyClass {
  static runtime;

  static {
    try {
      MyClass.runtime = `Node ${process.version.replace("v", "")}`;
    } catch {
      MyClass.runtime = "It is probably Deno";
    }
  }
}

console.log(MyClass.runtime);
node index.js
Node 17.8.0
deno run index.js
It is probably Deno

Error Cause

This propoasal lets us define the reason of abnormality in the cause property in an Error() constructor. This can be helpful to diagnose unexpected exceptions especially when the exception occured inside a deeply nested method.

async function fetchProfile() {
  // I made a mistake here in the API URL
  //                  👇👇👇👇
  const API = "https://api.api.github.com/users/pawelgrzybek";

  return await fetch(API)
    .then((r) => r.json())
    .catch(() => {
      throw new Error("Download raw resource failed", {
        cause: `Call to ${API}`, // 👈 👈 👈
      });
    });
}

try {
  await fetchProfile();
} catch (e) {
  console.log(e);
  // Error: Download raw resource failed
  console.log("Caused by", e.cause);
  // Caused by Call to https://api.api.github.com/users/pawelgrzybek
}

Comments

  • J
    John Rose

    "Currently, the only way to access the last element of an arr is arr[arr.length - 1]" What about arr.slice(-1)? Probably should be mentioned.

    👆 you can use Markdown here

    Your comment is awaiting moderation. Thanks!
    • Pawel Grzybek
      Pawel Grzybek

      Yes, you are absolutely right. I can think of more solution to that. Let me reword this sentence. Thanks John.

      👆 you can use Markdown here

      Your comment is awaiting moderation. Thanks!
    • S
      Sandro

      slice() returns a new array, not just a single element. So you would have to use list.slice(-1)[0].

      👆 you can use Markdown here

      Your comment is awaiting moderation. Thanks!
    • J
      John Smith

      What about […list].pop()?

      👆 you can use Markdown here

      Your comment is awaiting moderation. Thanks!
  • I
    Ibrahim Nergiz

    It's a nice summary. Thank you.

    👆 you can use Markdown here

    Your comment is awaiting moderation. Thanks!
    • Pawel Grzybek
      Pawel Grzybek

      Thanks Ibrahim. Have a fab day dude!

      👆 you can use Markdown here

      Your comment is awaiting moderation. Thanks!

Leave a comment

👆 you can use Markdown here

Your comment is awaiting moderation. Thanks!