Proposals included in the incoming ECMAScript 2022 standard for JavaScript

Brandon Lara
Geek Culture
Published in
6 min readSep 2, 2021

--

Photo by Fahrul Razi on Unsplash

ES2021 or ES12 was released earlier this summer, but many people are already thinking about the future, and what new features ES2022 will bring.

In this article, I will present and explain the proposals that have been accepted in the latest draft of the specification.

Each feature proposal follows a process in which it goes through different stages up to stage 4, which indicates that the addition is ready for inclusion in the formal ECMAScript standard, and will be included in the soonest practical standard revision. The following features are already finished proposals that are in stage 4 and are already added to the ECMAScript latest draft.

Class field declarations

So far in the ES specification, the class field definition and initialization was done in the constructor of the class. But with new the class fields proposal, the class fields can be defined and initialized on the top level of the class like this:

class Post{
title;
content;
shares = 0;
}

Private methods and fields

In this new way of defining class fields, the private ones now can also be defined with the # prefix like the example below:

class User {
name;
#password;
}

This is consistent with the class methods and accessors declarations, so the private methods and accessors can be defined with the # prefix as it's shown below:

class User {
name;
#password;
get #password(){
return #password;
}
#clear(){
this.name = null;
this.#password = null;
}
}

Static public methods and fields

This proposal adds the features of static public fields, static private method fields, and static private fields to JavaScript classes, building on the previous class fields and private methods proposals.

These features were created to follow the “static” aspects of the proposals for class fields and private methods, as shown in the following example:

class Environment {
name;
port;
static hostname = 'localhost';
static get hostname(){
return hostname;
}
}

Static methods are usually utility functions, such as functions for creating or cloning objects, and static fields are useful when you want a field to exist only once in each class instead of on every class instance you create. This is useful for caching, fixed-configuration, or any other data that does not need to be replicated across instances.

Regexp Match Indices

This proposal provides a new /dflag to get additional information about the start and indices position end of each match in the input string.

The following code snippet shows clearly how the Regexp Match Indices proposal works:

const regexp = /test(\d)/g; //without the /d flag
const regexp2022 = /test(\d)/dg; //with the /d flag
const str = 'test1test2';const array = [...str.matchAll(regexp)];
const array2022 = [...str.matchAll(regexp2022)];
console.log(array[0]);
console.log(array2022[0]);
console.log(array[1]);
console.log(array2022[1]);

Top-level await

The top-level await allows using the await keyword outside async functions. This proposal allows modules to act as large asynchronous functions, so these ECMAScript modules can wait for resources so that other modules that import them have to wait for them before they start executing their own code.

Note that the following example is executed at the top level of the module:

import {getUser} from './data/user'

let user = await getUser();
//

It will work without a problem with this new proposal, but with the old behaviour it will output SyntaxError: await is only valid in async function

Ergonomic brand checks for Private Fields

When you try to access a public field that is not declared you simply get undefined, meanwhile accessing private fields throws an exception. Then, we can check if a class has a private field by testing if an exception is thrown or not when trying to access it. But this proposal introduces a more interesting solution, that consists in using the in operator that returns true if a specified property/field is in the specified object/class, and making it working with private fields as you can see in the following example code:

class User {
name;
#password;
get #password(){
return #password;
}
#clear(){
this.name = null;
this.#password = null;
}
static hasPassword(obj){
return #password in obj;
}
}

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

This proposal is a new Array method to get an element by a given index. This new method has the same behaviour as accessing with the bracket notation when the given index is positive, but when we give a negative integer index, it works like python’s “negative indexing”, which means that at() the method indexes with negative integers counting backwards from the last item of the array. So the method can be executed as array.at(-1) which has the same behaviour as array[array.length-1] as can be seen in the following example:

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

Accessible Object.prototype.hasOwnProperty()

SometimesObject.prototype can be unavailable or redefined. For example, Object.create(null) will create an object that does not inherit from Object.prototype, making its methods inaccessible. Also, you can’t be sure that calling .hasOwnProperty() really calls the built-in method, because it can be overwritten if you don't directly own every property of the object.

To avoid these problems, a common practice is using the call() method to call hasOwnProperty() like the example below:

const obj = { foo:'bar' }let hasFoo = Object.prototype.hasOwnProperty.call(obj, 'foo');console.log(hasFoo); //true

This proposal adds a Object.hasOwn(object, property) method with the same behaviour as calling Object.prototype.hasOwnProperty.call(object, property). This new hasOwn(object, property)method provides an accessible way to check object properties more convenient than previous solutions, as you can see below:

const obj = { foo:'bar' }let hasFoo = Object.hasOwn(obj, 'foo');console.log(hasFoo); //true

ECMAScript class static initialization blocks

Class static blocks proposal provides an elegant way to evaluate static initialization blocks of code during the class declaration/definition, with access to private fields of the class.

The current proposals for static fields and static private fields provide a mechanism to perform per-field initialization of the static-side of a class during ClassDefinitionEvaluation, however there are some cases that cannot be covered easily. For example, if you need to evaluate statements during initialization (such as try..catch), or set two fields from a single value, you have to perform that logic outside of the class definition.

This can be understood with the following example:

Without static blocks:


class User {
static roles;
name;
#password;
}

try {
User.roles = getRolesFromDb();
} catch {
User.roles = getRolesFromBackup();
}

With static blocks:

class User {
static roles;
name;
#password;
static {
try {
User.roles = getRolesFromDb();
} catch {
User.roles = getRolesFromBackup();
}
}
}

As you can see in this example, there is not a big difference between the two solutions, since the static block is quite simple and small. However, if static blocks are not used, these kinds of initializations would be less elegant, clear or readable as the complexity of the code block grows.

This is all for the moment, if you have any doubts or suggestions about the subject, please do not hesitate to let me know.

Greetings.

You can support me by clicking on the following button:

I will appreciate and remember it forever ❤

References and more info:

--

--