Как стать автором
Обновить
1117.45
OTUS
Цифровые навыки от ведущих экспертов

Рабочие предложения, включенные в грядущий стандарт ECMAScript 2022 для JavaScript

Время на прочтение6 мин
Количество просмотров9K
Автор оригинала: Brandon Lara

Только ES2021 (или ES12) был зарелижен этим летом, как многие члены сообщества уже начали заглядывать в будущее, размышляя, в частности, о том, какие новые фичи принесет нам ES2022.

В этой статье вашему вниманию будут представлены и объяснены некоторые из предложений, которые были приняты в последнем драфте спецификации.

Каждое предложение фичи должно следовать определенному сценарию, в рамках которого оно проходит несколько стадий отбора вплоть до четвертой (stage 4), которая указывает на то, что это дополнение готово для включения в формальный стандарт ECMAScript и будет доступно в его ближайшей ревизии. Следующие фичи являются уже готовыми рабочими предложениями, которые находятся на четвертой стадии и уже добавлены в последний драфт ECMAScript.

Объявления полей класса

До сих пор в спецификации ES определение и инициализация поля класса выполнялись в конструкторе класса. Но благодаря этому новому предложению, поля класса могут быть определены и инициализированы на верхнем уровне класса следующим образом:

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

Приватные методы и поля

Благодаря этому новому способу определения полей класса теперь также можно определять приватные поля — посредством префикса #, как показано в примере ниже:

class User {
    name;
    #password;
}

Это работает и с объявлениями методов и ацессоров класса, т.е. методы и ацессоры также могут быть определены как приватные с помощью префикса #, как показано ниже:

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

Статические публичные методы и поля

Это предложение привносит в спецификацию функционал статических публичных полей, статических приватных методов и статических приватных полей в классах JavaScript, базируясь на предыдущих предложениях полей классов и приватных методов.

Этот функционал был задуман, чтобы покрыть “статические” аспекты предложений с полями классов и приватными методами, являясь по сути их логическим следствием, как мы видим в следующем примере:

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

Статические методы обычно представляют собой служебные функции, например, для создания или клонирования объектов, а статические поля нужны, когда вы хотите, чтобы поле существовало в единственном экземпляре на весь класс, а не в каждом его инстансе, который вы создаете. Это полезно для кэширования, фиксирования конфигурации или любых других данных, которые не нужно реплицировать между инстансами.

Индексы совпадений регулярных выражений

Это предложение предоставляет новый флаг /d для получения информации о начальной и конечной позиции по каждому индексу совпадений, найденных во входной строке.

Следующий фрагмент кода показывает, как работает это предложение:

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]);

Верхнеуровневый await  

Верхнеуровневый await дает нам возможность использовать ключевое слово await вне асинхронных функций. Это предложение позволяет модулям действовать как большие асинхронные функции, т.е. эти модули ECMAScript могут ожидать ресурсы, так что другие модули, которые их импортируют, также должны ждать их, прежде чем они начнут выполнять свой собственный код.

Обратите внимание, что следующий пример выполняется на верхнем уровне модуля:

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

let user = await getUser();
//

Благодаря этому новому предложению код выше будет работать без проблем, а в старой спецификации он будет выводить SyntaxError: await is only valid in async function

Эргономичный brand-checking для приватных полей

Когда вы попытаетесь получить доступ к публичному полю, которое не объявлено, вы попросту получите undefined, при этом доступ к приватным полям вызывает исключение. Исходя из этого, мы можем проверить, имеет ли класс приватное поле, проверив, генерируется ли исключение при попытке доступа к нему. Но это предложение предоставляет нам более элегантное решение, заключающееся в использовании оператора in, который возвращает true, если указанное свойство/поле находится в указанном объекте/классе, заставляя его работать с приватными полями, как вы можете видеть в следующем примере кода:

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

Новый метод .at() для всех встроенных индексируемых сущностей

Это предложение представляет собой новый метод Array, позволяющий получить элемент по заданному индексу. Когда мы подставляем в этот метод положительный индекс, он ведет себя так же, как и стандартный доступ через скобки, но когда мы подставляем отрицательный целочисленный индекс, он работает как “отрицательная индексация” в Python, т.е. будет производится отсчет в обратном порядке от последнего элемента массива. Таким образом, поведение метода в таком виде array.at(-1) будет аналогично array[array.length-1], что можно увидеть в следующем примере:

const array = [0,1,2,3,4,5];

console.log(array[array.length-1]); // 5
console.log(array.at(-1)); //5
//то же поведение

console.log(array[array.lenght-2]); // 4
console.log(array.at(-2)); //4
//то же поведение

Доступный Object.prototype.hasOwnProperty()

Иногда Object.prototype может быть недоступен или переопределен. Например, Object.create(null) создаст объект, который не наследуется от Object.prototype, что сделает его методы недоступными. Кроме того, вы не можете быть уверены, что вызов .hasOwnProperty() действительно вызывает встроенный метод, потому что он может быть перезаписан, если вы не владеете напрямую каждым свойством объекта.

Чтобы избежать этих проблем, для вызова hasOwnProperty() обычно используется метод call(), как показано в примере ниже:

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

Это предложение добавляет метод Object.hasOwn(object, property), который ведет себя также, как и вызов Object.prototype.hasOwnProperty.call(object, property). Этот новый метод hasOwn(object, property) предоставляет нам доступный способ проверки свойств объекта, более удобный, чем предыдущие решения, как вы можете видеть ниже:

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

Блоки статической инициализации классов ECMAScript

Это предложение даем нам элегантный способ вычисления блоков статической инициализации кода во время объявления/определения класса с доступом к его приватным полям.

Текущие предложения касательно статических и статических приватных полей предоставляют механизм для выполнения инициализации статической части класса по каждому полю во время ClassDefinitionEvaluation, однако есть некоторые случаи, которые реализовать так легко. Например, если вам нужно вычислить операторы во время инициализации (например, try..catch) или установить два поля из одного значения, вы должны выполнить эту логику вне определения класса.

Это можно понять на следующем примере:

Без статических блоков:

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

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

Со статическими блоками:

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

Как вы можете видеть в этом примере, между двумя решениями особой разницы нет, поскольку статический блок довольно простой и небольшой. Однако, если не использовать статические блоки, то по мере роста сложности блока кода эти виды инициализации будут менее элегантными, наглядными и удобочитаемыми.

На этом все, если у вас есть какие-либо сомнения или предложения по этому поводу, пожалуйста, дайте мне знать.

А также, привет!

Ссылки и дополнительная информация:


Материал подготовлен в рамках специализации "Fullstack Developer"

Всех желающих приглашаем на бесплатное demo-занятие «Такие разные числа!». На занятии будут рассмотрены такие типы данных в JavaScript, как number и bigint, а также особенности их устройства и операций с ними.
>> РЕГИСТРАЦИЯ

Теги:
Хабы:
Всего голосов 9: ↑8 и ↓1+10
Комментарии12

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS