3
10 фич JavaScript, которые можно начать использовать прямо сейчас | Паблико
6 подписчики

10 фич JavaScript, которые можно начать использовать прямо сейчас


27 июл 2022 · 03:06    

Новые возможности ECMAScript 2022 включают в себя ожидание на верхнем уровне, индексы соответствия RegExp, новые поля классов public и private и многое другое. Давайте приступим!



imgpreview.jpg 78.72 KB


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

Спецификация ES13 привносит восемь новых возможностей для JavaScript. Давайте начнем знакомство с этими новыми возможностями, которые вы можете использовать уже сегодня.

Поля классов

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

Публичные и приватные поля экземпляра

Ранее стандартным подходом при объявлении поля-члена внутри ключевого слова class было введение его в конструктор. Новейшая спецификация ECMAScript позволяет нам определять член встраиваемого поля как часть тела класса. Как показано в примере 1, мы можем использовать хэштег для обозначения приватного поля.

Пример 1. Совмещаем публичные и приватные поля класса:

class Song {
title = «»;
#artist = «»;
constructor(title, artist){
this.title = title;
this.#artist = artist;
}
}
let song1 = new Song(«Only a Song», «Van Morrison» );
console.log(song1.title);
// outputs “Only a Song”
console.log(song1.artist);
// outputs undefined

В первом примере мы определяем класс Song, используя ключевое слово class. Этот класс имеет два члена, название и исполнитель. Член artist имеет префикс в виде символа хэша, поэтому он является приватным. Мы разрешаем устанавливать эти поля в конструкторе. Обратите внимание, что конструктор должен обращаться к this.# artist с префиксом хэша еще раз, иначе он перезапишет поле публичным членом.

Далее мы определяем экземпляр класса Song, устанавливая оба поля через конструктор. Затем мы выводим поля в консоль. Дело в том, что song1.artist не виден внешнему миру и выводит неопределенное значение.

Заметим также, что даже song1.hasOwnProperty(«artist» ) вернет false. Кроме того, мы не сможем создать приватные поля класса позже с помощью присваивания.

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

Методы и аксессоры частных экземпляров

Символ хэша также работает как префикс для методов и аксессоров. Влияние на видимость точно такое же, как и в случае с приватными полями экземпляра. Так, вы можете добавить приватный сеттер и публичный геттер к полю Song.artist, как показано в примере 2.

Пример 2. Методы и аксессоры частных экземпляров:

class Song {
title = «»;
#artist = «»;
constructor(title, artist){
this.title = title;
this.#artist = artist;
}
get getArtist() {
return this.#artist;
}
set #setArtist(artist) {
this.#artist = artist;
}
}

Статические члены

Предложение о полях класса также вводит статические члены. Они выглядят и работают аналогично тому, как это делается в Java: если член имеет ключевое слово-модификатор static, то он существует в классе, а не в экземплярах объектов. Вы можете добавить статический член в класс Song, как показано в примере 3.

Пример 3. Добавление статического члена в класс:

class Song {
static label = «Exile»;
}

Тогда поле будет доступно только через имя класса, Song.label. В отличие от Java, экземпляры JavaScript не хранят ссылку на общую статическую переменную. Обратите внимание, что можно иметь статическое приватное поле со статической #label; то есть приватное статическое поле.

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

Regex match был обновлен, чтобы включать больше информации о группах соответствия. По соображениям производительности эта информация включается только в том случае, если к регулярному выражению добавлен флаг /d. (Более подробное описание значения /d regex см. в RegExp Match Indices for ECMAScript).

В принципе, использование флага /d заставляет механизм regex включать начало и конец всех совпадающих подстрок. Когда флаг присутствует, свойство indices в результатах exec будет содержать двумерный массив, где первое измерение представляет совпадение, а второе - начало и конец совпадения.

В случае именованных групп в индексах будет присутствовать член под названием groups, первое измерение которого содержит имя группы. Рассмотрим пример 4, который взят отсюда.

Пример 4. Индексы групп Regex:

const re1 = /a+(?<Z>z)?/d;

// block 1
const s1 = «xaaaz»;
const m1 = re1.exec(s1);
m1.indices[0][0] === 1;
m1.indices[0][1] === 5;
s1.slice(...m1.indices[0]) === «aaaz»;

// block 2
m1.indices[1][0] === 4;
m1.indices[1][1] === 5;
s1.slice(...m1.indices[1]) === «z»;

// block 3
m1.indices.groups[«Z» ][0] === 4;
m1.indices.groups[«Z» ][1] === 5;
s1.slice(...m1.indices.groups[«Z» ]) === «z»;

// block 4
const m2 = re1.exec(«xaaay» );
m2.indices[1] === undefined;
m2.indices.groups[«Z» ] === undefined;

В примере 4 мы создаем регулярное выражение, которое соответствует символу a один или более раз, а затем именованную группу соответствия (с именем Z), которая соответствует символу z ноль или более раз.

В первом блоке кода демонстрируется, что m1.indices[0][0] и m1.indices[0][1] содержат 1 и 5 соответственно. Это потому, что первым совпадением для regex является строка от первого a до строки, заканчивающейся на z. Блок 2 показывает то же самое для символа z.

В блоке 3 показан доступ к первому измерению с именованной группой через m1.indices.groups. Есть одна совпадающая группа - последний символ z, и она имеет начало 4 и конец 5.

Наконец, блок 4 демонстрирует, что несопоставленные индексы и группы возвращают неопределенный результат.

В итоге, если вам нужен доступ к деталям сопоставления групп в строке, теперь вы можете использовать функцию regex match indices для их получения.

Высокоуровневое ожидание

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

В примере 5 приведен пример, заимствованный отсюда.

Пример 5. Высокоуровневый await

// awaiting.mjs
import { process } from «./some-module.mjs»;
const dynamic = import(computedModuleSpecifier);
const data = fetch(url);
export const output = process((await dynamic).default, await data);
// usage.mjs
import { output } from «./awaiting.mjs»;
export function outputPlusValue(value) { return output + value }

console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100), 1000);

Обратите внимание в файле awaiting.mjs на ключевое слово await перед использованием зависимых модулей dynamic и data. Это означает, что когда usage.mjs импортирует awaiting.mjs, usage.mjs не будет выполняться, пока зависимости awaiting.mjs не закончат загрузку.

Новые эргономичные проверки для приватных полей

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

В примере 6 показан этот новый, эргономичный способ проверки наличия приватного поля изнутри класса с помощью ключевого слова in.

Пример 6. Проверка существования приватного поля:

class Song {
#artist;
checkField(){
return #artist in this;
}
}
let foo = new Song();
foo.checkField(); // true

Пример 6 является надуманным, но идея понятна. Когда вам понадобится проверить класс на наличие закрытого поля, вы можете использовать формат:# fieldName in object.

Отрицательная индексация с помощью.at()

Прошли времена arr[arr.length -2]. Метод .at для встроенных индексируемых элементов теперь поддерживает отрицательные индексы, как показано в примере 7.

Пример 7. Отрицательный индекс с помощью.at():

let foo = [1,2,3,4,5];
foo.at(3); // == 3
hasOwn

hasOwn

Object.hasOwn - это улучшенная версия Object.hasOwnProperty. Она работает в некоторых исключительных случаях, например, когда объект создается с помощью Object.create(null). Обратите внимание, что hasOwn является статическим методом - он не существует для экземпляров.

Пример 8. hasOwn() в действии:

let foo = Object.create(null);
foo.hasOwnProperty = function(){};
Object.hasOwnProperty(foo, 'hasOwnProperty'); // Error: Cannot convert object to primitive value
Object.hasOwn(foo, 'hasOwnProperty'); // true

В примере 8 показано, что вы можете использовать Object.hasOwn для экземпляра foo, созданного с помощью Object.create(null).

Статический блок класса

Вот шанс для разработчиков Java сказать: «О, у нас это было с 90-х годов». ES 2022 вводит в JavaScript статические блоки инициализации. По сути, вы можете использовать ключевое слово static в блоке кода, который запускается при загрузке класса, и он будет иметь доступ к статическим членам.

В примере 9 приведен простой пример использования статического блока для инициализации статического значения.

Пример 9. Статический блок:

class Foo {
static bar;
static {
this.bar = “test”;
}
}

Причина ошибки

И последнее, но не менее важное: класс Error теперь включает в себя поддержку причин. Это позволяет использовать в цепочках ошибок стековые трассировки, подобные Java. Конструктор ошибок теперь позволяет использовать объект options, который включает поле cause, как показано в примере 10.

Пример 10. Причина ошибки:

throw new Error('Error message', { cause: errorCause });

Заключение

Понравилась статья? Тогда ставьте лайки, пишите комментарии, делитесь ею с друзьями, а также подписывайтесь на нас тут и на других площадках (ссылка в шапке профиля).

Новые возможности ECMAScript 2022 включают в себя ожидание на верхнем уровне, индексы соответствия RegExp, новые поля классов public и private и многое другое. Давайте приступим!



imgpreview.jpg 78.72 KB


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

Спецификация ES13 привносит восемь новых возможностей для JavaScript. Давайте начнем знакомство с этими новыми возможностями, которые вы можете использовать уже сегодня.

Поля классов

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

Публичные и приватные поля экземпляра

Ранее стандартным подходом при объявлении поля-члена внутри ключевого слова class было введение его в конструктор. Новейшая спецификация ECMAScript позволяет нам определять член встраиваемого поля как часть тела класса. Как показано в примере 1, мы можем использовать хэштег для обозначения приватного поля.

Пример 1. Совмещаем публичные и приватные поля класса:

class Song {
title = «»;
#artist = «»;
constructor(title, artist){
this.title = title;
this.#artist = artist;
}
}
let song1 = new Song(«Only a Song», «Van Morrison» );
console.log(song1.title);
// outputs “Only a Song”
console.log(song1.artist);
// outputs undefined

В первом примере мы определяем класс Song, используя ключевое слово class. Этот класс имеет два члена, название и исполнитель. Член artist имеет префикс в виде символа хэша, поэтому он является приватным. Мы разрешаем устанавливать эти поля в конструкторе. Обратите внимание, что конструктор должен обращаться к this.# artist с префиксом хэша еще раз, иначе он перезапишет поле публичным членом.

Далее мы определяем экземпляр класса Song, устанавливая оба поля через конструктор. Затем мы выводим поля в консоль. Дело в том, что song1.artist не виден внешнему миру и выводит неопределенное значение.

Заметим также, что даже song1.hasOwnProperty(«artist» ) вернет false. Кроме того, мы не сможем создать приватные поля класса позже с помощью присваивания.

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

Методы и аксессоры частных экземпляров

Символ хэша также работает как префикс для методов и аксессоров. Влияние на видимость точно такое же, как и в случае с приватными полями экземпляра. Так, вы можете добавить приватный сеттер и публичный геттер к полю Song.artist, как показано в примере 2.

Пример 2. Методы и аксессоры частных экземпляров:

class Song {
title = «»;
#artist = «»;
constructor(title, artist){
this.title = title;
this.#artist = artist;
}
get getArtist() {
return this.#artist;
}
set #setArtist(artist) {
this.#artist = artist;
}
}

Статические члены

Предложение о полях класса также вводит статические члены. Они выглядят и работают аналогично тому, как это делается в Java: если член имеет ключевое слово-модификатор static, то он существует в классе, а не в экземплярах объектов. Вы можете добавить статический член в класс Song, как показано в примере 3.

Пример 3. Добавление статического члена в класс:

class Song {
static label = «Exile»;
}

Тогда поле будет доступно только через имя класса, Song.label. В отличие от Java, экземпляры JavaScript не хранят ссылку на общую статическую переменную. Обратите внимание, что можно иметь статическое приватное поле со статической #label; то есть приватное статическое поле.

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

Regex match был обновлен, чтобы включать больше информации о группах соответствия. По соображениям производительности эта информация включается только в том случае, если к регулярному выражению добавлен флаг /d. (Более подробное описание значения /d regex см. в RegExp Match Indices for ECMAScript).

В принципе, использование флага /d заставляет механизм regex включать начало и конец всех совпадающих подстрок. Когда флаг присутствует, свойство indices в результатах exec будет содержать двумерный массив, где первое измерение представляет совпадение, а второе - начало и конец совпадения.

В случае именованных групп в индексах будет присутствовать член под названием groups, первое измерение которого содержит имя группы. Рассмотрим пример 4, который взят отсюда.

Пример 4. Индексы групп Regex:

const re1 = /a+(?<Z>z)?/d;

// block 1
const s1 = «xaaaz»;
const m1 = re1.exec(s1);
m1.indices[0][0] === 1;
m1.indices[0][1] === 5;
s1.slice(...m1.indices[0]) === «aaaz»;

// block 2
m1.indices[1][0] === 4;
m1.indices[1][1] === 5;
s1.slice(...m1.indices[1]) === «z»;

// block 3
m1.indices.groups[«Z» ][0] === 4;
m1.indices.groups[«Z» ][1] === 5;
s1.slice(...m1.indices.groups[«Z» ]) === «z»;

// block 4
const m2 = re1.exec(«xaaay» );
m2.indices[1] === undefined;
m2.indices.groups[«Z» ] === undefined;

В примере 4 мы создаем регулярное выражение, которое соответствует символу a один или более раз, а затем именованную группу соответствия (с именем Z), которая соответствует символу z ноль или более раз.

В первом блоке кода демонстрируется, что m1.indices[0][0] и m1.indices[0][1] содержат 1 и 5 соответственно. Это потому, что первым совпадением для regex является строка от первого a до строки, заканчивающейся на z. Блок 2 показывает то же самое для символа z.

В блоке 3 показан доступ к первому измерению с именованной группой через m1.indices.groups. Есть одна совпадающая группа - последний символ z, и она имеет начало 4 и конец 5.

Наконец, блок 4 демонстрирует, что несопоставленные индексы и группы возвращают неопределенный результат.

В итоге, если вам нужен доступ к деталям сопоставления групп в строке, теперь вы можете использовать функцию regex match indices для их получения.

Высокоуровневое ожидание

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

В примере 5 приведен пример, заимствованный отсюда.

Пример 5. Высокоуровневый await

// awaiting.mjs
import { process } from «./some-module.mjs»;
const dynamic = import(computedModuleSpecifier);
const data = fetch(url);
export const output = process((await dynamic).default, await data);
// usage.mjs
import { output } from «./awaiting.mjs»;
export function outputPlusValue(value) { return output + value }

console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100), 1000);

Обратите внимание в файле awaiting.mjs на ключевое слово await перед использованием зависимых модулей dynamic и data. Это означает, что когда usage.mjs импортирует awaiting.mjs, usage.mjs не будет выполняться, пока зависимости awaiting.mjs не закончат загрузку.

Новые эргономичные проверки для приватных полей

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

В примере 6 показан этот новый, эргономичный способ проверки наличия приватного поля изнутри класса с помощью ключевого слова in.

Пример 6. Проверка существования приватного поля:

class Song {
#artist;
checkField(){
return #artist in this;
}
}
let foo = new Song();
foo.checkField(); // true

Пример 6 является надуманным, но идея понятна. Когда вам понадобится проверить класс на наличие закрытого поля, вы можете использовать формат:# fieldName in object.

Отрицательная индексация с помощью.at()

Прошли времена arr[arr.length -2]. Метод .at для встроенных индексируемых элементов теперь поддерживает отрицательные индексы, как показано в примере 7.

Пример 7. Отрицательный индекс с помощью.at():

let foo = [1,2,3,4,5];
foo.at(3); // == 3
hasOwn

hasOwn

Object.hasOwn - это улучшенная версия Object.hasOwnProperty. Она работает в некоторых исключительных случаях, например, когда объект создается с помощью Object.create(null). Обратите внимание, что hasOwn является статическим методом - он не существует для экземпляров.

Пример 8. hasOwn() в действии:

let foo = Object.create(null);
foo.hasOwnProperty = function(){};
Object.hasOwnProperty(foo, 'hasOwnProperty'); // Error: Cannot convert object to primitive value
Object.hasOwn(foo, 'hasOwnProperty'); // true

В примере 8 показано, что вы можете использовать Object.hasOwn для экземпляра foo, созданного с помощью Object.create(null).

Статический блок класса

Вот шанс для разработчиков Java сказать: «О, у нас это было с 90-х годов». ES 2022 вводит в JavaScript статические блоки инициализации. По сути, вы можете использовать ключевое слово static в блоке кода, который запускается при загрузке класса, и он будет иметь доступ к статическим членам.

В примере 9 приведен простой пример использования статического блока для инициализации статического значения.

Пример 9. Статический блок:

class Foo {
static bar;
static {
this.bar = “test”;
}
}

Причина ошибки

И последнее, но не менее важное: класс Error теперь включает в себя поддержку причин. Это позволяет использовать в цепочках ошибок стековые трассировки, подобные Java. Конструктор ошибок теперь позволяет использовать объект options, который включает поле cause, как показано в примере 10.

Пример 10. Причина ошибки:

throw new Error('Error message', { cause: errorCause });

Заключение

Понравилась статья? Тогда ставьте лайки, пишите комментарии, делитесь ею с друзьями, а также подписывайтесь на нас тут и на других площадках (ссылка в шапке профиля).

Читайте также

Комментарии 0

Войдите для комментирования
НОВОСТИ ПОИСК РЕКОМЕНД. НОВОЕ ЛУЧШЕЕ ПОДПИСКИ