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! 👩🏻‍💻

Discussion (68)

Collapse
baraa_baba profile image
Baraa Baba

I will miss arr[arr.Length -2]

Collapse
jasmin profile image
Jasmin Virdi Author

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
atulcodex profile image
Atul Prajapati

Ohh wow

Collapse
jasmin profile image
Jasmin Virdi Author

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 Author

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 on

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 Author • Edited on

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

Thanks👍

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 Author

😁

Collapse
jiimaho profile image
Jim Aho

Can you give an example as of why?

/ C# dude here

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 Author

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 Author • Edited on

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
IroncladDev

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 on

flatMap operator is alternative but sure its nice to have

Collapse
lico profile image
SeongKuk Han

Thank you for sharing the post. :)

Collapse
jasmin profile image
Jasmin Virdi Author

🙂

Collapse
mat3uszkek profile image
Mateusz Skrobiś

superb post, thanks.

Collapse
jasmin profile image
Jasmin Virdi Author

🙂

Collapse
mdkawsarislam2002 profile image
Md Kawsar Islam Yeasin

Wow Thanks ❤️

Collapse
jasmin profile image
Jasmin Virdi Author

🙂

Collapse
arthur322 profile image
Arthur Conrado de Lima

Excellent article! Thanks!

Collapse
macadoshis profile image
Saad BENBOUZID

Laughing in typescript

(JK, very interesting !)

Collapse
jwp profile image
John Peters

Excellent summary Tx.

Collapse
jasmin profile image
Jasmin Virdi Author

Thank you! 👍🏻

Collapse
steveplays profile image
Steveplays

Great post Jasmin! Very informative.

Collapse
jasmin profile image
Jasmin Virdi Author

Thank you! 👍

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 Author

Hey,

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

Collapse
sahan profile image
Sahan

Thanks for the breakdown. Nicely written too 👏

Collapse
jasmin profile image
Jasmin Virdi Author

Thanks👍

Collapse
alenmorgan profile image
Alen Morgan

I had so much fun learning with you. Your lessons were very insightful and interactive, so thank you.

Collapse
jasmin profile image
Jasmin Virdi Author

Glad to hear 😄

Thanks for going through my articles👍

Collapse
msp99000 profile image
MiKee

Really useful, honestly learned new features. Thanks

Collapse
jasmin profile image
Jasmin Virdi Author

Thanks👍

Collapse
sachiicoding profile image
sachiicoding

Great job jasmin.. its very nice for students like me..

Collapse
jasmin profile image
Jasmin Virdi Author

Thanks 👍

Collapse
sem1colons profile image
Youssef Abdulaziz

Thanks a lot, appreciate your time

Collapse
jasmin profile image
Jasmin Virdi Author

🙂

Collapse
Sloan, the sloth mascot
Comment deleted
Collapse
jasmin profile image
Jasmin Virdi Author • Edited on

Hey,

It is index based that is why the element at 3rd index would be 4 as per what is mentioned in the example 🤔

Collapse
romulocintra profile image
romulocintra:dev

That's a nice summary please looking forward to see you around TC39 Educators call @jasmin github.com/tc39/js-outreach-groups

Collapse
jasmin profile image
Jasmin Virdi Author

Hey,

Thank you soo much. Can you please share more details about this?😅

Collapse
romulocintra profile image
romulocintra:dev

Hello, you can fill a form there github.com/tc39/js-outreach-groups then I can invite you for our next meeting :)

Thread Thread
jasmin profile image
Jasmin Virdi Author

Thank you so much!
Filled the form!🙂

Collapse
konaduakwasiakuoko profile image
Konadu Akwasi Akuoko

Thanks for writing this 😘
I really love your theme 🤩🔥, please what theme is it?

Collapse
jasmin profile image
Jasmin Virdi Author

Thank you 👍🏻
I have used JS code blocks which does the Javascript style highlighting.

Collapse
syedmeesamali profile image
syedmeesamali

pipe? I was sure it would be there ....

Collapse
jwenjian profile image
Jiang Wenjian

So, we can use await in any where, no need to wrap in an async method?

Collapse
elijahtrillionz profile image
Elijah Trillionz

await without async functions 🤪 that's really a good one.
Also can't wait for the array find-from-last object.

Collapse
darwinphi profile image
Darwin Manalo

I'm still waiting for the pipe operator 🙈🙈

Collapse
oanouman profile image
Martial Anouman

Great summary. Thanks

Collapse
gers2017 profile image
Gers2017

why did they chose # to declare private properties? I don't love the syntax tbh but I guess is better than nothing

Collapse
leob profile image
leob

Looks more like an incremental upgrade, nothing revolutionary here ...