Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Ожидается, что версия ECMAScript 2021 будет выпущена в июне 2021 года. Вот некоторые из функций, которые могут оказаться в ES2021 или ES12. Список подготовлен на основе ECMAScript Proposals и новых функций, выпущенных движком Google Chrome V8.
Все функции, перечисленные ниже, на момент написания поддерживаются в сборке Google Chrome Canary (версия браузера Google Chrome, поддерживающая экспериментальные возможности).
Метод String replaceAll()
String.prototype.replaceAll() заменяет все вхождения строки другим строковым значением.
В настоящее время в JavaScript у строк есть метод replace(). Его можно использовать для замены подстроки другой строкой.
const str = "Backbencher sits at the Back";
const newStr = str.replace("Back", "Front");
console.log(newStr); // "Frontbencher sits at the Back"
Если входной шаблон для замены является строкой, метод replace() заменяет только первое вхождение. Поэтому в коде второе вхождение «Back» не заменяется.
Мы можем сделать полную замену, только если предоставим шаблон для замены в виде регулярного выражения.
const str = "Backbencher sits at the Back";
const newStr = str.replace(/Back/g, "Front");
console.log(newStr); // "Frontbencher sits at the Front"
String.prototype.replaceAll() пытается произвести замену всех вхождений, даже если входной шаблон является строкой.
const str = "Backbencher sits at the Back";
const newStr = str.replaceAll("Back", "Front");
console.log(newStr); // "Frontbencher sits at the Front"
Приватные методы
Приватные методы могут быть доступны только внутри класса, в котором они определены. Имена приватных методов начинаются с символа #.
class Person {
// Приватный метод
#setType() {
console.log("I am Private");
}
// Публичный метод
show() {
this.#setType();
}
}
const personObj = new Person();
personObj.show(); // "I am Private";
personObj.setType(); // TypeError: personObj.setType is not a function
Поскольку setType() является частным методом, personObj.setType возвращает значение undefined. Попытка использовать undefined в качестве функции вызывает ошибку TypeError.
Приватные аксессоры
Функции-аксессоры (get/set) можно сделать приватными, добавив # к имени функции.
class Person {
// Публичные аксессоры
get name() { return "Backbencher" }
set name(value) {}
// Приватные аксессоры
get #age() { return 42 }
set #age(value) {}
}
В приведенном выше коде ключевые слова get и set делают name аксессором. Несмотря на то, что name выглядит как функция, его можно читать как обычное свойство.
const obj = new Person();
console.log(obj.name); // "Backbencher"
console.log(obj.age); // undefined
WeakRef
WeakRef означает слабые ссылки (Weak References). В основном слабые ссылки используются для реализации кэшей или маппингов больших объектов. В таких сценариях мы не хотим удерживать большое количество памяти надолго, сохраняя редко используемый кэш или маппинг. Мы можем разрешить сборку мусора для памяти в ближайшее время, а позже, если она нам снова понадобится, мы можем создать свежий кэш.
JavaScript - это язык со сборкой мусора. Если переменная больше недоступна, сборщик мусора JavaScript автоматически удаляет ее. Вы можете узнать больше о сборке мусора JavaScript здесь, на сайте MDN.
Рассмотрим следующий код:
const callback = () => {
const aBigObj = {
name: "Backbencher"
};
console.log(aBigObj);
};
(async function(){
await new Promise((resolve) => {
setTimeout(() => {
callback();
resolve();
}, 2000);
});
})();
Код может показаться сложным. Но здесь мы всего лишь создаем функцию с именем callback() и выполняем ее с помощью setTimeout(). Асинхронная обёртка предназначена только для использования функции await. await - это функция в ES6, которая помогает синхронно выполнять асинхронный код.
При выполнении указанного выше кода через 2 секунды выводится «Backbencher». В зависимости от того, как мы используем функцию callback(), переменная aBigObj может храниться в памяти вечно.
Давайте сделаем aBigObj слабой ссылкой.
const callback = () => {
const aBigObj = new WeakRef({
name: "Backbencher"
});
console.log(aBigObj.deref().name);
}
(async function(){
await new Promise((resolve) => {
setTimeout(() => {
callback(); // Гарантированно напечатает "Backbencher"
resolve();
}, 2000);
});
await new Promise((resolve) => {
setTimeout(() => {
callback(); // Нет гарантий, что напечатается "Backbencher"
resolve();
}, 5000);
});
})();
WeakRef создается с помощью new WeakRef(). Позже ссылка читается с помощью метода .deref(). Внутри асинхронной функции первый setTimeout() обязательно напечатает значение name. Это гарантируется на первом этапе цикла обработки событий после создания слабой ссылки.
Но нет гарантии, что второй setTimeout() напечатает «Backbencher». Слабая ссылка могла быть освобождена сборщиком мусора. Поскольку сборка мусора в разных браузерах работает по-разному, мы не можем гарантировать результат. Вот почему мы используем WeakRef в таких ситуациях, как управление кэшем.
Финализаторы
FinalizationRegistry - это дополнительная функция WeakRef. Он позволяет программистам регистрировать коллбеки, которые будут вызываться после того, как объект был забран сборщиком мусора.
const registry = new FinalizationRegistry((value) => {
console.log(value);
});
Здесь registry является экземпляром FinalizationRegistry. Функция обратного вызова (коллбек), переданная в FinalizationRegistry, срабатывает при сборке мусора.
(function () {
const obj = {};
registry.register(obj, "Backbencher");
})();
Строка 3 привязыват obj к registry. Когда obj забирает сборщик мусора, второй аргумент метода .register() передается функции обратного вызова. Итак, согласно нашей логике, когда obj забирает сборщик мусора, «Backbencher» передается функции обратного вызова и печатается в консоли.
При выполнении приведенного выше кода в консоли Google Chrome Canary, примерно через 1 минуту, он напечатал «Backbencher» в консоли. Еще один способ принудительно выполнить сборку мусора в Chrome - щелкнуть на иконку «Собрать мусор». Мы можем найти его во вкладке «Производительность».
Promise.any() и AggregateError
Promise.any() успешно завершается, если успешно завершился любой из предоставленных в качестве аргументов промис. Ниже у нас есть 3 промиса, которые выполняются в случайное время.
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve("A"), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve("B"), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve("C"), Math.floor(Math.random() * 1000));
});
Promise.any() возвращает результат первого успешно завершившегося промиса среди p1, p2 и p3.
(async function() {
const result = await Promise.any([p1, p2, p3]);
console.log(result); // Печатает "A", "B" или "C"
})();
Что, если ни один из промисов не завершится успешно? В таком случае Promise.any() сгенерирует исключение AggregateError. Нам нужно поймать это исключение и обработать.
const p = new Promise((resolve, reject) => reject());
try {
(async function() {
const result = await Promise.any([p]);
console.log(result);
})();
} catch(error) {
console.log(error.errors);
}
В демонстрационных целях в Promise.any() передается только один промис. И этот промис завершается «с ошибкой» (reject). Приведенный выше код выведет следующую ошибку в консоли.
Оператор логического присваивания
Оператор логического присваивания объединяет логические операции (&&, || или ??) с присваиванием.
let x = 1;
let y = 2;
x &&= y;
console.log(x); // 2
Строка 3 эквивалентна следующему выражению:
x && (x = y)
Или по-другому:
if(x) {
x = y
}
Поскольку x - истинное значение, ему присваивается значение y, то есть 2.
Как и в случае с &&, мы можем поступить так же и с логическими операциями || и ??.
Оператор логического присваивания с ||
Пример кода.
let x = 1;
let y = 2;
x ||= y;
console.log(x); // 1
Строка 3 эквивалентна следующему выражению:
x || (x = y)
Это означает, что операция присваивания происходит, только если x является ложным значением. В нашем коде x содержит 1, что является истинным значением, и, следовательно, присваивания не происходит. Вот почему наш код выводит 1 в консоли.
Оператор логического присваивания с ??
?? - это оператор нулевого присваивания (Nullish Coalescing operator) в JavaScript. Конкретно, при присвоении оператор проверяет, является ли левый операнд null или undefined и если это так, то вычисляет и присваивает правый операнд. Если же левый операнд не null и не undefined, то присваивается он.
let a;
let b = a ?? 5;
console.log(b); // 5
В строке 2, если значение a равно null или undefined, правая часть ?? вычисляется и присваивается переменной b.
Давайте теперь рассмотрим ?? вместе с =.
let x;
let y = 2;
x ??= y;
console.log(x); // 2
Строка 2 в коде выше эквивалентна следующему выражению:
x = x ?? (x = y)
Здесь значение x равно undefined. Таким образом, выражение в правой части вычисляется и устанавливает x равным 2.