DEV Community

Cover image for What's new in ES2022? 🤔
Jasmin Virdi
Jasmin Virdi

Posted on • Updated on

What's new in ES2022? 🤔

Soon the new version of ECMA Script will become standard in few months. So let's take a glimpse at the features that will be part of ES2022.

Features of ES2022

1. Method .at() of indexable values.

This function let's us reads an element at the given index. It can accept negative indexes to read elements from the end of the given datatype.

For example

[1,2,3,4,5].at(3)  // returns 4

[1,2,3,4,5].at(-2)   // returns 4
Enter fullscreen mode Exit fullscreen mode

Datatypes supporting this function.

  • String
  • Array
  • All Typed Array classes: Uint8Array etc.

2. RegExp match indices

Adding a flag /d to a regular expression produces match objects that records the start and end of each group capture.

There are different ways to match indices

  • Match indices for numbered group
const matchObj = /(a+)(b+)/d.exec('aaaabb');

console.log(matchObj);
/*
Output -
['aaaabb', 'aaaa', 'bb', index: 0, input: 'aaaabb', groups: undefined, indices: Array(3)]
*/
Enter fullscreen mode Exit fullscreen mode

Due to the regular expression flag /d, matchObj also has a property .indices that records for each numbered group where it was captured in the input string.

matchObj.indices[1];
/*
Output - 
[0, 4]
*/
Enter fullscreen mode Exit fullscreen mode
  • Match indices for named groups
const matchObj = /(?<as>a+)(?<bs>b+)/d.exec('aaaabb');

console.log(matchObj);
/*
Output - 
['aaaabb', 'aaaa', 'bb', index: 0, input: 'aaaabb', groups: {as: 'aaaa', bs: 'bb'}, indices: Array(3)]
*/
Enter fullscreen mode Exit fullscreen mode

Their indices are stored in matchObj.indices.groups

matchObj.indices.groups;
/*
Output -
{ as: [0,4], bs: [4,6] }
*/
Enter fullscreen mode Exit fullscreen mode

3. Object.hasOwn(obj, propKey)

It is a safe way to check that propKey is the own property of obj object. It is similar to Object.prototype.hasOwnProperty but it supports all object types.

const proto = {
  protoProp: 'protoProp',
};

const obj = {
  __proto__: proto,
  objProp: 'objProp',
};

console.log('protoProp' in obj); // output - true.
console.log(Object.hasOwn(obj, 'protoProp')) // output - false
console.log(Object.hasOwn(proto, 'protoProp')); // output - true.
Enter fullscreen mode Exit fullscreen mode

4. error.cause

Error and it's subclasses now let us specify the reason behind the error. This is useful in deeply nested function where we have chained error blocks to quickly find the error. Read here for more info

function readFiles(filePaths) {
  return filePaths.map(
    (filePath) => {
      try {
        // ···
      } catch (error) {
        throw new Error(
          `While processing ${filePath}`,
          {cause: error}
        );
      }
    });
}
Enter fullscreen mode Exit fullscreen mode

5. Top-level await modules

We can now use await at the top levels of modules and don’t have to enter async functions or methods anymore.

  • Loading modules dynamically
const messages = await import(`./messages-${language}.mjs`);
Enter fullscreen mode Exit fullscreen mode
  • Using a fallback if module loading fails
let lodash;
try {
  lodash = await import('https://primary.example.com/lodash');
} catch {
  lodash = await import('https://secondary.example.com/lodash');
}
Enter fullscreen mode Exit fullscreen mode
  • Using whichever resource loads fastest
const resource = await Promise.any([
  fetch('http://example.com/first.txt')
    .then(response => response.text()),
  fetch('http://example.com/second.txt')
    .then(response => response.text()),
]);
Enter fullscreen mode Exit fullscreen mode

6. New members of classes

  • Public properties can be created via
    • Instance public fields
class InstPublicClass {
  // Instance public field
  instancePublicField = 0; // (A)

  constructor(value) {
    // We don’t need to mention .property elsewhere!
    this.property = value; // (B)
  }
}

const inst = new InstPublicClass('constrArg');
Enter fullscreen mode Exit fullscreen mode
  • Static public fields
const computedFieldKey = Symbol('computedFieldKey');
class StaticPublicFieldClass {
  static identifierFieldKey = 1;
  static 'quoted field key' = 2;
  static [computedFieldKey] = 3;
}
console.log(StaticPublicFieldClass.identifierFieldKey) //output -> 1
console.log(StaticPublicFieldClass['quoted field key']) //output -> 2
console.log(StaticPublicFieldClass[computedFieldKey]) //output -> 3
Enter fullscreen mode Exit fullscreen mode
  • Private slots are new and can be created via
    • Instance private fields
class InstPrivateClass {
  #privateField1 = 'private field 1'; // (A)
  #privateField2; // (B) required!
  constructor(value) {
    this.#privateField2 = value; // (C)
  }
  /**
   * Private fields are not accessible outside the class body.
   */
  checkPrivateValues() {
  console.log(this.#privateField1); // output -> 'private field 1'
  console.log(this.#privateField2); // output -> 'constructor argument'

  }
}

const inst = new InstPrivateClass('constructor argument');
  inst.checkPrivateValues();


console.log("inst", Object.keys(inst).length === 0) //output -> inst, true
Enter fullscreen mode Exit fullscreen mode
  • Instance and static private fields
class InstPrivateClass {
  #privateField1 = 'private field 1'; // (A)
  #privateField2; // (B) required!
  static #staticPrivateField = 'hello';
  constructor(value) {
    this.#privateField2 = value; // (C)
  }
  /**
   * Private fields are not accessible outside the class body.
   */
  checkPrivateValues() {
    console.log(this.#privateField1); // output -> 'private field 1'
    console.log(this.#privateField2); // output -> 'constructor argument'

  }

  static #twice() {
    return this.#staticPrivateField + " " + this.#staticPrivateField;
  }

  static getResultTwice() {
    return this.#twice()
  }
}

const inst = new InstPrivateClass('constructor argument');
inst.checkPrivateValues();


console.log("inst", Object.keys(inst).length === 0) //output -> "inst", true
console.log(InstPrivateClass.getResultTwice()); // output -> "hello hello"
Enter fullscreen mode Exit fullscreen mode
  • Private methods and accessors
class MyClass {
  #privateMethod() {}
  static check() {
    const inst = new MyClass();

    console.log(#privateMethod in inst) // output-> true

    console.log(#privateMethod in MyClass.prototype) // output-> false

    console.log(#privateMethod in MyClass) // output-> false
  }
}
MyClass.check();
Enter fullscreen mode Exit fullscreen mode
  • Static initialisation blocks in classes. For static data we have Static fields and Static Blocks that are executed when the class is created.
class Translator {
  static translations = {
    yes: 'ja',
    no: 'nein',
    maybe: 'vielleicht',
  };
  static englishWords = [];
  static germanWords = [];
  static { // (A)
    for (const [english, german] of Object.entries(this.translations)) {
      this.englishWords.push(english);
      this.germanWords.push(german);
    }
  }
}


console.log(Translator.englishWords, Translator.germanWords)
//Output -> ["yes", "no", "maybe"], ["ja", "nein", "vielleicht"]
Enter fullscreen mode Exit fullscreen mode
  • Private slot checks - This functionality helps us to check that the object has the given private slot in it.
class C1 {
  #priv() {}
  static check(obj) {
    return #priv in obj;
  }
}

console.log(C1.check(new C1())) // output true
Enter fullscreen mode Exit fullscreen mode

These amazing features will help us to enhance our projects and improve our coding techniques. I am really excited to try these features out in my project. 💃

Happy Coding! 👩🏻‍💻

Top comments (75)

Collapse
 
baraa_baba profile image
Baraa Baba

I will miss arr[arr.Length -2]

Collapse
 
jasmin profile image
Jasmin Virdi

True 😅

Collapse
 
maxart2501 profile image
Massimo Artizzu

... or not! 😅

Collapse
 
blessinghirwa profile image
Blessing Hirwa

I didn't like this one. It could mislead me sometimes 😂/

Collapse
 
ardunster profile image
Anna R Dunster

Don't worry, you can still use it if you want ;)

Collapse
 
adnane_ch profile image
Adnane Chaikhi

hhhhhhhhhhhhhhhhh

Collapse
 
idabdellah profile image
Mohamed ID-ABDELLAH

so true hahahahah

Collapse
 
atulcodex profile image
🚩 Atul Prajapati 🇮🇳

Ohh wow

Collapse
 
jasmin profile image
Jasmin Virdi

Thanks👍

Collapse
 
mindplay profile image
Rasmus Schultz

What is error.cause for?

Normally, the cause of the error is what I would put in the error message. I mean, what else would you put there?

Why do we need another field for that?

I don't know of any other language that has two text messages in the same exception. What for? 🤷‍♂️

Collapse
 
abea profile image
Alex Bea

The error message might sometimes be used for a public-facing message. You could then put more technical information in the cause as well. That's my guess, at least.

Collapse
 
mindplay profile image
Rasmus Schultz

Ah, mystery solved!

2ality.com/2021/06/error-cause.html

It's for chaining errors - like the "inner exception" you have in many other languages.

Because you can throw anything in JS, the property type isn't specified as Error - but the intention is similar.

Thread Thread
 
jasmin profile image
Jasmin Virdi

Thanks for attaching this link for reference. 🙂

The way this would be super helpful is in deeply nested functions with chained errors.
Like if we have mutiple try catch block inside a deeply nested function so we pass the string as the purpose of that block and cause as the argument of catch block. For example:

function deeplyNested() {
  try {
    // outer block logic.

    let appData = [{...}]
    // app data array parsing.
    appData.map(
      (data) => {
        try {
          // ···
        } catch (error) {
          throw new Error(`While processing ${data}`, {
            cause: error
          });
        }
      });
  } catch (error) {
    throw Error('Error while processing outer block', {
      cause: error
    });
  }
}

Enter fullscreen mode Exit fullscreen mode
Collapse
 
mindplay profile image
Rasmus Schultz

That sounds unlikely?

At least, I've never heard of anyone using exceptions for display purposes - exceptions generally do contain technical information, they are usually intended for developers, not for users. How would you deal with localization, for instance... That's just not what exceptions are for...

Collapse
 
juvpengele profile image
Juvenal PENGELE • Edited

I may be wrong but I do not think this is correct "For static data we have Static fields and Static Blocks that are executed every time a new instance is created.".

Static blocks are evaluated once during Class definition not every time a new instance is created.
When a new instance is created, it is the code in the construction that is executed.

Collapse
 
jasmin profile image
Jasmin Virdi • Edited

Yes you are right, static blocks are executed when a class is created not in case of instance. Updated the statement.

Thanks👍

Collapse
 
brettz9 profile image
Brett Zamir

Informative post, thank you. There is apparently an error in the output listed for matchObj.indices.groups however which should instead by an object keyed by group.

Collapse
 
jasmin profile image
Jasmin Virdi

Hey,

Actually, I included the full output which is an array having an object keyed by group.

I should’ve included just the groups output for more clarity.
Thanks for pointing out buddy!😀👍

Collapse
 
brettz9 profile image
Brett Zamir

This is what I see as the output showing on the page:

matchObj.indices.groups;
/*
Output -
[0,4]
*/
Enter fullscreen mode Exit fullscreen mode

There's no object showing there...

Thread Thread
 
jasmin profile image
Jasmin Virdi • Edited

I was referring to the snippet just above this one 😅
I should’ve returned the full object instead of returning just the indices.

Updated the post. Thanks 👍

Collapse
 
ironcladdev profile image
Conner Ow

Top-level await is what I've been waiting for forever!!

Can't wait for these to come out!!

Collapse
 
sanidz profile image
sanidz • Edited

flatMap operator is alternative but sure its nice to have

Collapse
 
stereoplegic profile image
Mike Bybee

I'm very excited for being able to use the top level await examples you gave (minus the lodash part).

Collapse
 
jasmin profile image
Jasmin Virdi

😁

Collapse
 
jiimaho profile image
Jim Aho

Can you give an example as of why?

/ C# dude here

Collapse
 
mat3uszkek profile image
Mateusz Skrobiś

superb post, thanks.

Collapse
 
jasmin profile image
Jasmin Virdi

🙂

Collapse
 
lico profile image
SeongKuk Han

Thank you for sharing the post. :)

Collapse
 
jasmin profile image
Jasmin Virdi

🙂

Collapse
 
sahan profile image
Sahan

Thanks for the breakdown. Nicely written too 👏

Collapse
 
jasmin profile image
Jasmin Virdi

Thanks👍

Collapse
 
zyabxwcd profile image
Akash

Short and crisp. Thumbs up for that but one minor feedback though, it would have been great if practical/possible use cases around it would have been shown or told on top of the syntax. Cheers!

Collapse
 
jasmin profile image
Jasmin Virdi • Edited

Thanks for sharing the feedback. Will definitely work on it. 🙌

Collapse
 
jwp profile image
John Peters

Excellent summary Tx.

Collapse
 
jasmin profile image
Jasmin Virdi

Thank you! 👍🏻

Collapse
 
steveplays profile image
Steveplays

Great post Jasmin! Very informative.

Collapse
 
jasmin profile image
Jasmin Virdi

Thank you! 👍

Collapse
 
macadoshis profile image
Saad BENBOUZID

Laughing in typescript

(JK, very interesting !)

Collapse
 
qq449245884 profile image
qq449245884

Dear Jasmin Virdi,may I translate your all dev articles into Chinese?I would like to share it with more developers in China. I will give the original author and original source.

Collapse
 
jasmin profile image
Jasmin Virdi

Hey,

Sure please go ahead. Do tag me in the post so that I can see it too!👍