Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Только 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();
}
}
}
Как вы можете видеть в этом примере, между двумя решениями особой разницы нет, поскольку статический блок довольно простой и небольшой. Однако, если не использовать статические блоки, то по мере роста сложности блока кода эти виды инициализации будут менее элегантными, наглядными и удобочитаемыми.
На этом все, если у вас есть какие-либо сомнения или предложения по этому поводу, пожалуйста, дайте мне знать.
А также, привет!
Ссылки и дополнительная информация:
https://github.com/tc39/proposals/blob/master/finished-proposals.md
https://2ality.com/2021/09/class-static-block.html
https://tc39.es/process-document/
https://tc39.es/ecma262/
https://v8.dev/features/top-level-await
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static
Материал подготовлен в рамках специализации "Fullstack Developer"
Всех желающих приглашаем на бесплатное demo-занятие «Такие разные числа!». На занятии будут рассмотрены такие типы данных в JavaScript, как number и bigint, а также особенности их устройства и операций с ними.
>> РЕГИСТРАЦИЯ