[Перевод] 5 возможностей JavaScript ES12, которыми стоит воспользоваться уже сегодня
Стандарт ECMAScript 2021 (12 редакция) выпущен 22 июня 2021 года. Вместе с ним появились новые возможности и новые синтаксические конструкции. Все эти улучшения направлены на то, чтобы сделать JavaScript надёжнее и стабильнее, чтобы разработчикам легче было делать своё дело.
Я подробно расскажу о 5 самых интересных возможностях ECMAScript 2021. Это позволит вам приступить к их использованию в своих проектах, что упростит вам работу и улучшит ваш код. Эта статья может оказаться полезной как начинающим, так и опытным разработчикам.
1. Разделители разрядов чисел
Разделители разрядов чисел позволяют записывать числовые литералы с использованием символов подчёркивания, что улучшает читабельность чисел. Система автоматически удаляет эти символы при подготовке кода к запуску. В следующем коде демонстрируется пример использования разделителей.
// Десятичное число, разряды которого разделены символом подчёркивания.
let n1 = 1_000_000_000;
console.log(n1); // Выведет: 1000000000
// Десятичное число, разряды которого разделены символом подчёркивания.
let n2 = 1_000_000_000.150_200
console.log(n2); // Выведет: 1000000000.1502
// Шестнадцатеричное число, байты которого разделены символом подчёркивания.
let n3 = 0x95_65_98_FA_A9
console.log(n3); // Выведет: 641654651561
// BigInt-число, разряды которого разделены символом подчёркивания.
let n4 = 155_326_458_156_248_168_514n
console.log(n4); // This will print: 155326458156248168514n
2. Метод String.prototype.replaceAll ()
Новый метод строковых объектов replaceAll()
позволяет заменить на что либо все вхождения подстроки в строке. При использовании строкового метода replace()
осуществляется лишь замена первого вхождения искомого значения. А метод replaceAll()
позволяет заменить все вхождения такого значения. Вот пример:
// Объявляем константу, хранящую некое строковое значение.
const orgStr = 'JavaScript, often abbreviated as JS, is a programming language that conforms to the ECMAScript specification. JavaScript is high-level, often just-in-time compiled and multi-paradigm.';
// Для того чтобы заменить в исходной строке лишь первое вхождение искомой подстроки и сформировать новую строку - воспользуемся методом replace().
let newStr = orgStr.replace('JavaScript', 'TypeScript');
console.log(newStr);
// Для замены всех вхождений искомой строки воспользуемся методом replaceAll().
let newStr2 = orgStr.replaceAll('JavaScript', 'TypeScript');
console.log(newStr2);
3. Метод Promise.any () и объект AggregateError
Метод Promise.any()
можно назвать полной противоположностью метода Promise.all()
. Promise.any()
, при передаче ему итерируемого объекта с промисами, возвращает промис со значением первого успешно выполненного промиса. Если ни один из промисов не разрешён — метод возвращает сведения об ошибках, в частности — объект AggregateError
. А Promise.all()
ждёт разрешения всех промисов. Есть и другие методы объекта Promise
. Например — Promise.allSettled()
, который ожидает успешного завершения или отклонения всех переданных ему промисов.
Рассмотрим пример:
// Создаём объект Promise.
const promise1 = new Promise((resolve, reject) => {
// Разрешить промис через 2 секунды.
setTimeout(() => resolve("The first promise has been resolved."), 2000);
});
// Создаём объект Promise.
const promise2 = new Promise((resolve, reject) => {
// Разрешить промис через 1 секунду.
setTimeout(() => resolve("The second promise has been resolved."), 1000);
});
// Создаём объект Promise.
const promise3 = new Promise((resolve, reject) => {
// Разрешить промис через 3 секунды.
setTimeout(() => resolve("The third promise has been resolved."), 3000);
});
(async function () {
const data = await Promise.any([promise1, promise2, promise3]);
// Выводим данные, возвращённые из первого разрешённого промиса.
console.log(data);
// Предыдущая команда выведет следующее: The second promise has been resolved.
})()
Если все промисы были отклонены — будет возвращён объект AggregateError
, содержащий сведения об ошибках. Обратитесь к следующему примеру для того чтобы разобраться с тем, как обрабатывать подобные ошибки:
// Создаём объект Promise.
const promise1 = new Promise((resolve, reject) => {
// Отклонить промис через 1 секунду.
setTimeout(() => reject("The first promise has been rejected."), 1000);
});
// Создаём объект Promise.
const promise2 = new Promise((resolve, reject) => {
// Отклонить промис через 500 миллисекунд.
setTimeout(() => reject("The second promise has been rejected."), 500);
});
// Попытаемся выполнить промисы.
(async function () {
try {
const data = await Promise.any([promise1, promise2]);
console.log(data);
} catch (error) {
// Если все промисы отклонены, мы попадём в этот блок try-catch, где
// можно будет обработать ошибки, с которыми завершилась работа промисов.
console.log("Error: ", error);
}
})();
4. Логические операторы присваивания
В ECMAScript 2021 появились три новых оператора, которые представляют собой комбинацию оператора присваивания и логических операторов.
- Логический оператор присваивания ИЛИ (OR):
||=
. - Логический оператор присваивания И (AND):
&&=
. - Логический оператор присваивания с проверкой значений на
null
иundefined
:??=
.
▍4.1. Оператор ||=
Оператор ||=
принимает два операнда и назначает правый операнд левому только в том случае, если левый операнд является ложным. Вот пример:
// Оператор ||= проверит, не является ли ложным (0) значение songsCount.
// Если это так, правый операнд будет записан в переменную, находящуюся в левой части выражения.
let myPlaylist = {songsCount: 0, songs:[]};
myPlaylist.songsCount ||= 100;
console.log(myPlaylist); // Выведет: {songsCount: 100, songs: Array(0)}
Этот оператор работает по сокращённой схеме вычислений. Он эквивалентен следующему выражению, в котором используется логический оператор ИЛИ:
a || (a = b)
▍4.2. Оператор &&=
Оператор &&=
присваивает правый операнд левому только в том случае, если значение, находящееся слева, является истинным. Рассмотрим пример:
// Оператор &&= проверит, является ли значение filesCount истинным.
// Если это так - правый операнд будет присвоен левому.
let myFiles = {filesCount: 100, files:[]};
myFiles.filesCount &&= 5;
console.log(myFiles); // Выведет: {filesCount: 5, files: Array(0)}
Оператор &&=
тоже работает по сокращённой схеме вычислений. Этот оператор эквивалентен следующему выражению, в котором используется логический оператор И:
a && (a = b)
▍4.3. Оператор ?=
Оператор ??=
присвоит правый операнд левому только в том случае, если левый оператор представлен значением null
или undefined
. Например:
// Оператор ??= проверит, равняется ли lastname null или undefined.
// Если это так - правый операнд будет присвоен левому.
let userDetails = {firstname: 'Katina', age: 24}
userDetails.lastname ??= 'Dawson';
console.log(userDetails); // Выведет: {firstname: 'Katina', age: 24, lastname: 'Dawson'}
5. Приватные методы экземпляров классов и методы доступа к свойствам
Свойства и методы экземпляров классов в JavaScript, по умолчанию, общедоступны. Но теперь можно создавать приватные методы и свойства с использованием префикса #
. Доступны они только изнутри экземпляра класса. Вот как пользоваться приватными методами:
// Создадим класс User.
class User {
constructor() {}
// Приватный метод можно создать, поместив '#' перед
// именем метода.
#generateAPIKey() {
return "d8cf946093107898cb64963ab34be6b7e22662179a8ea48ca5603f8216748767";
}
getAPIKey() {
// Обратиться к приватному методу можно, поставив '#' перед
// именем метода.
return this.#generateAPIKey();
}
}
const user = new User();
const userAPIKey = user.getAPIKey();
console.log(userAPIKey); // Выведет: d8cf946093107898cb64963ab34be6b7e22662179a8ea48ca5603f8216748767
Приватные методы доступа к свойствам объектов — это приватные геттеры и сеттеры. Геттер позволяет получить значение свойства, а сеттер позволяет назначить свойству значение.
Объявить приватный геттер можно так:
get #newAccountPassword() {}
Так можно объявить приватный сеттер:
set #generateAccountPassword(newPassword) {}
Вот как ими пользоваться:
// Создадим класс Str.
class Str {
// Приватные свойства можно создавать, помещая '#'
// перед их именами.
#uniqueStr;
constructor() {}
// Приватный сеттер можно создать, поместив '#' перед
// его именем.
set #generateUniqueStringByCustomLength(length = 24) {
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let randomStr = "";
for (let i = 0; i < length; i++) {
const randomNum = Math.floor(Math.random() * characters.length);
randomStr += characters[randomNum];
}
this.#uniqueStr = randomStr;
}
// Общедоступный сеттер
set setRandomString(length) {
this.#generateUniqueStringByCustomLength = length;
}
// Приватный геттер можно создать, поместив '#' перед
// его именем.
get #fetchUniqueString() {
return this.#uniqueStr;
}
// Общедоступный геттер
get getRandomString() {
return this.#fetchUniqueString;
}
}
const str = new Str();
// Вызываем общедоступный сеттер, который обратится к приватному сеттеру,
// находящемуся в том же объекте, что и он.
str.setRandomString = 20;
// Вызываем общедоступный геттер, который обратится к приватному геттеру,
// находящемуся в том же объекте, что и он.
const uniqueStr = str.getRandomString;
console.log(uniqueStr); // Выводит случайную строку каждый раз, когда геттер вызывают после вызова сеттера
Итоги
Теперь вы знаете, как пользоваться некоторыми новыми возможностями JavaScript ES12 (ECMAScript 2021). А значит — пришло время применить эти знания на практике.
Пользуетесь ли вы возможностями JavaScript ES12 в своих проектах?