JavaScript  —  это легкий для освоения язык программирования, что делает его весьма подходящим для начинающих. За многие годы он развился до такой степени, что охватил практически все сферы разработки. Это и фронтенд (React, Angular или Vue.js), и бэкенд (Node.js), и создание десктопных приложений с помощью ElectronJS, список можно продолжить.

В 2021 году этот язык обзавелся рядом новых полезных возможностей, в число которых вошли:

1. Новые логические операторы

В JS появилось три новых логических оператора, а именно &&=, ||= и ??=. Рассмотрим их подробнее.

Оператор &&=:

Начнем с примера:

let a = 1;
let b = 2;
a &&= b;
console.log(a) // выводом для переменной 'a' будет 2.

Строка a&&= b аналогична следующему коду:

if(a) {
  a = b;
}

Этот логический оператор говорит, что если переменная a содержит истинное значение (а так и есть, поскольку ее значение ненулевое), тогда ей должно быть присвоено значение переменной b. Именно поэтому, когда выполняется console.log(a), значение переменной a оценивается как 2, а не 1.

Оператор ||=:

Рассмотрим следующий код:

let a = 1;
let b = 2;
a ||= b;
console.log(b); // выводом для переменной 'a' будет 1.

Этот оператор противоположен оператору &&=. Здесь переменная a будет равна переменной b только, если переменная a содержит ложное значение. Вышеприведенный код равнозначен фрагменту ниже:

if (!a) {
  a = b;
}

Оператор ??=:

Этот оператор проверяет, является ли значение null или undefined. Взглянем на пример:

let a;
let b = 2;
a ??= 1;
console.log(a) // выводом для переменной 'a' будет 1.

// этот блок кода аналогичен фрагменту приведенному выше.
// if(a === null || a === undefined) {
//   a = 1
// }

В данном примере значение переменной a оценивается как undefined, значит условие if оценивается как true и a присваивается значение 1.

2. Строковый метод ‘replaceAll’ 

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

Пример:

// без regex
let str = 'JS is everywhere. JS is amazing!';
console.log(str.replace('JS', 'JavaScript')); // выводом будет 'JavaScript is everywhere. JS is amazing!'

// с regex
let str = 'JS is everywhere. JS is amazing!';
console.log(str.replace(/JS/g, 'JavaScript')); // выводом будет 'JavaScript is everywhere. JavaScript is amazing!'.

С помощью метода replaceAll необходимость в регулярных выражения отпала. Рассмотрим код ниже:

let str = 'JS is everywhere. JS is amazing!';
console.log(str.replaceAll('JS', 'JavaScript')); // выводом будет 'JavaScript is everywhere. JavaScript is amazing!'.

let str = 'JS is everywhere. JS is amazing!';
console.log(str.replaceAll('JS', 'JavaScript')); // выводом будет 'JavaScript is everywhere. JavaScript is amazing!'.

Метод replaceAll заменяет все вхождения заданного символа или слова на нужный элемент.

3. Нижние подчеркивания для разделения целых чисел

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

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

let number = 1_000_000_000; // один миллиард
console.log(number) // 1000000000 (это значение останется целым числом)

4. ‘Promise.any()’

Promise.any() — это новая функция, которая получает несколько итерируемых промисов и возвращает тот из них, который выполняется первым. На примере будет более понятно:

const p1 = new Promise(resolve => setTimeout(resolve, 500, 'First'));
const p2 = new Promise(resolve => setTimeout(resolve, 800, 'Second'));
const p3 = Promsie.reject(1);

const promises = [p1, p2, p3];

Promise.any(promises)
.then(result => {
   console.log(result);
}) // результатом будет 'First', потому что этот промис выполняется первым
.catch(e => {
    console.log(e);
})

Если ни один из промисов не выполнится, выводом будет AggregateError. Для обработки AggregateError мы определяем после инструкции then инструкцию catch.

5. WeakRef и Финализаторы

WeakRef  —  это сокращение для “Weak References” (слабая ссылка). WeakRef позволяет удерживать слабую ссылку на объект. Удерживаемая таким образом ссылка называется “цель”. Важно отметить, что слабая ссылка не препятствует удалению объекта сборщиком мусора.

Сбор мусора — это метод сбора утративших свою надобность переменных с целью освобождения памяти. 

Примечание: WeakRef следует использовать только в частных случаях и по возможности лучше избегать.

Разберем пример:

const weakRefFunc = () => {
    const obj = new WeakRef({
       name: 'JavaScript'
    });
    console.log(obj.deref().name);
}
const test = () => {
    new Promise(resolve => {
     setTimeout(() => {
       weakRefFunc();
        resolve();
      }, 3000)
    })
    new Promise(resolve => {
     setTimeout(() => {
       weakRefFunc();
        resolve();
      }, 5000)
    })
}
test();

Метод deref возвращает удерживаемую цель. Если цель оказывается удалена сборщиком мусора, тогда возвращается undefined.

В этом примере переменная obj является удерживаемой слабой ссылкой.

При первом вызове weakrefFunc в функции test гарантированно выводится “JavaScript”, но во втором вызове вывод “JavaScript” уже не гарантируется, поскольку переменная obj будет удалена сборщиком мусора.

Финализаторы 

Финализатор чаще всего используется совместно с Weakref, но иногда и отдельно. Его задача  —  уведомлять об удалении объекта сборщиком мусора. Разберем на примере:

→ Сначала создадим финализатор с помощью метода FinalizationRegistry.

const registerFinalizer = new FinalizationRegistry(data => console.log(data));

const obj = {'name': 'JavaScript'};
registerFinalizer.register(obj, 'obj is collected now!')

Теперь переменная registerFinalizer является объектом, содержащим метод register, который мы будем использовать.

registerFinalizer.register получает два аргумента. Первый  —  это объект, отслеживаемый на предмет удаления сборщиком, а второй —  это сообщение, которое будет выводиться в консоли при удалении данного объекта.

Теперь, когда сборщик мусора удалит переменную obj, в консоли отобразиться сообщение “obj is now collected!”.

Заключение

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

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

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Tirlochan Arora: JavaScript 2021: New Features

Предыдущая статьяТестирование уровня данных в Android Room с помощью Rxjava, LiveData и сопрограмм Kotlin
Следующая статьяКак запустить любое ПО с графическим интерфейсом в Docker?