Шесть возможностей JavaScript ES12, которые следует использовать

Источник: «Top 6 JavaScript ES12 Features You Should Use»
Ещё в 2015 году была представлена революционная версия ES6 с множеством функций, широко используемых в современной веб-разработке.

С тех пор ECMAScript претерпел значительные изменения вплоть до версии ES12, официально известной как ECMAScript 2021. ES12 появился в июне 2021 года с новыми возможностями, улучшениями и некоторыми изменениями синтаксиса.

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

1. Promise.any()

Promise.any() принимает набор объектов Promise и разрешает, если хоть один из этих промисов будет выполнен. Это полезно, когда нам нужно, чтобы только один из промисов был выполнен независимо от того, что происходит с другими.

Promise.all() — это аналогичный метод, который уже существовал в ECMAScript, но он разрешался только в том случае, если все промисы были разрешены. Аналогично, Promise.race() использовался для возврата первого промиса, завершившего выполнение, независимо от того, разрешён он или отклонён.

const err = new Promise((resolve, reject) => {
reject(new Error('Error'));
});
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('First Promise');
}, 200);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Second Promise');
}, 500);
});
Promise.any(\\\[err, p1, p2\\\]).then((res) => {
console.log(res);
})
// output: First Promise

Новый класс ES12 — AggregateError позволяет перехватывать исключения метода Promise.any(). Например, если все промисы, переданные в Promise.any(), будут отклонены, то будет выброшен объект AggregateError.

const e1 = new Promise((resolve, reject) => {
reject(new Error('Error 1'));
});
const e2 = new Promise((resolve, reject) => {
reject(new Error('Error 2'));
});
Promise.any(\\\[e1, e2\\\])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
// output: "AggregateError: All promises were rejected"

Использование Promise.any() в разработке довольно простое. Например, мы можем отправить несколько одинаковых вызовов API на сервер или в базу данных и вернуть данные независимо от того, какой из них пришёл первым.

2. WeakRef

Как следует из названия, WeakRef — это слабая ссылка на другой объект. Объект со слабой ссылкой не будет храниться в памяти до тех пор, пока на него нет сильной ссылки.

JavaScript использует алгоритм сборки мусора для удаления из памяти объектов, на которые больше не ссылаются другие объекты. Поэтому, когда мы создаём объект WeakRef, он может быть собран в любой момент.

const student = {
name: 'John Doe',
age: 20,
address: {
number: 365,
street: 'Flower street'
}
}
const ref = new WeakRef(student);
ref.deref().age;
//output: 20

Мы можем использовать метод deref() для доступа к слабой ссылке, если она ещё доступна в памяти.

Несмотря на то, что WeakRef полезен для экономии памяти, авторы WeakRef советуют по возможности избегать его использования, что объясняется сложным поведением сборщиков мусора в различных движках JavaScript.

3. Приватные методы класса

С момента появления классов в JavaScript в ES6 методы и свойства по умолчанию были публичными. Даже если разработчики использовали префикс подчёркивания (_) при объявлении приватных методов и свойств, это было всего лишь условностью.

Это не мешало никому обращаться к приватным свойствам извне класса. Но в ES12 JavaScript позволил создавать приватные методы и свойства нативно. Для того чтобы создать такой метод, необходимо добавить к его идентификатору хэш (#).

class Auth {
#getToken() {
return "12345678";
}
isAuth() {
return this.#getToken();
}
}
const auth = new Auth();
auth.getToken(); //output: auth.getToken is not a function
auth.isAuth(); //output: 12345678

Аналогично приватным методам и свойствам в JavaScript ES12, мы можем определять приватные аксессоры (геттеры и сеттеры), используя тот же синтаксис.

class Auth {
get #getToken() {
return localStorage.getItem('token');
}
set #setToken(token) {
localStorage.setItem('token', token);
}
set login(token) {
this.#setToken = token;
}
get isAuth() {
return this.#getToken;
}
}
let token = '12345678';
const auth = new Auth();
auth.login = token;
auth.isAuth; //output: 12345678

4. Операторы логического присваивания

JavaScript уже поддерживает арифметические и побитовые операторы присваивания. Начиная с ES12, в нем расширена поддержка логических операторов присваивания.

Появились три новых оператора логического присваивания:

Несмотря на то, что синтаксис оператора похож на синтаксис арифметического оператора присваивания (+=), логические операторы присваивания не всегда выполняют присваивание. Вместо этого присвоение будет происходить только в том случае, если выполняется условие, заданное логическим оператором.

4.1 Логическое нулевое (nullish) присваивание

Оператор логического нулевого (nullish) присваивания (??=) присваивает значение правого операнда левому операнду только в том случае, если левый операнд равен null или undefined (nullish).

На первый взгляд, оператор ??= может показаться несколько запутанным, поскольку его развёрнутая форма эквивалентна x ?? (x = y).

const person = { name: 'John' };
person.name ??= 'User 1';
console.log(person.name);
// output: John
person.age ??= 18;
console.log(person.age);
// output: 18

Если бы мы использовали более старую версию ECMAScript, то приведённый выше код выглядел бы следующим образом:

const person = { name: 'John' };
if(person.name === undefined || person.name === null) {
person.name = 'User 1';
}
console.log(person.name);
if(person.age === undefined || person.age === null) {
person.age = 18;
}
console.log(person.age);

4.2 Присваивание логического И

Оператор логического присваивания И (&&=) выполнит присваивание, если левый операнд должен быть 'true'. Поскольку мы только что рассмотрели нулевое (nullish) присваивание, использование оператора логического присваивания И практически не требует пояснений.

const product = { stocks: 10 };
product.stocks &&= 20;
console.log(product.stocks);
// output: 20
product.exp &&= '12/31/2021';
console.log(product.exp);
// output: undefined

4.3 Присваивание логического ИЛИ

Оператор логического присваивания ИИ (||=) аналогичен присваиванию nullish, но для выполнения присваивания левый операнд должен быть false. Значение считается false, если оно равно null, undefined, false, 0 или NaN.

const product = {
stocks: 0,
exp: '12/31/2021'
};
product.stocks ||= 10;
console.log(product.stocks);
// output: 10
product.exp ||= '01/31/2022';
console.log(product.exp);
// output: 12/31/2021

5. String.replaceAll()

Назначение метода replaceAll() состоит в том, чтобы заменить все подстроки внутри строки. В предыдущих версиях ECMAScript для этого необходимо было использовать метод replace().

В методе replace() при использовании в качестве первого аргумента строки будет заменено только первое вхождение. Поэтому мы зададим в качестве первого аргумента регулярное выражение для замены всех вхождений.

let str = 'hotdog dog'.replace(new RegExp('dog','g'), 'cat');
console.log(str) //output: hotcat cat

В ES12 мы можем сразу использовать метод replaceAll() без применения регулярных выражений. Этот метод очень прост и безопасен.

let str = 'hotdog dog'.replaceAll('dog', 'cat');
console.log(str) //output: hotcat cat

6. Числовые разделители

Это простая, но полезная функция, которая уже была доступна в браузерах благодаря движку V8, но теперь она интегрирована в ES12. Числовые разделители — это символы подчёркивания (_), которые помогают нам разделять большие числа.

let billion = 1_000_000_000;
console.log(billion); //output: 1000000000

Браузер будет игнорировать символы подчёркивания. Числовые разделители облегчают жизнь разработчикам при работе с большими числами.

Примечание: Числа не могут начинаться или заканчиваться цифровым разделителем, а также нельзя использовать два или более знака подчёркивания вместе.

Подведение итогов

ECMAScript продолжает развиваться, с каждым годом добавляя новые возможности. 12-я редакция ES упростила основные функции кодирования, дополнив их новыми возможностями.

В этой статье мы рассмотрели шесть основных возможностей ES12, которые необходимо изучить разработчику JavaScript. Я надеюсь, что вы используете эти возможности в своих проектах.

Спасибо за внимание!

Дополнительные материалы

Предыдущая Статья

Знакомство с контейнерными запросами CSS

Следующая Статья

Рефакторинг CSS: Введение