Новые инструменты в JavaScript версии 11 (ES2020)

Раздел: JavaScript -> Версии JavaScript

Основные нововведения JavaScript 11 (ES2020)

Безопасный доступ к вложенным свойствам

Как получить значение глубоко вложенного свойства объекта без риска ошибки TypeError?

Для решения этой задачи введен оператор опциональной цепочки (?.). Он позволяет обратиться к свойству, и если промежуточное значение равно null или undefined, выражение прерывается и возвращает undefined. Например:
const user = { profile: { name: 'Анна' } };
const city = user?.address?.city; // undefined

Js 7 (javascript es7)

Результат: undefined, без ошибки.

Js 11 (javascript версия 11)

Этот подход сокращает код и делает его более читаемым.
Альтернативный вариант - использование логического оператора &&. Например:
const city = user && user.address && user.address.city;

версия js (версия javascript)

Однако такой код становится громоздким при большой вложенности. Другой вариант - функция с проверкой, но это увеличивает объем кода.
Типичная ошибка: забыть, что опциональная цепочка работает только для null/undefined, а не для других ложных значений (0, ''). Другая проблема - чрезмерное использование, которое может скрыть неожиданные отсутствия данных. Рекомендуется применять осознанно и комбинировать с оператором объединения с null (??).

Замена значений по умолчанию для null/undefined

Как задать значение по умолчанию, если переменная равна null или undefined, но не пустой строке или нулю?

Оператор объединения с null (??) возвращает правый операнд только если левый равен null или undefined. Это отличается от логического ||, который срабатывает на любые ложные значения.
const count = 0;
const defaultCount = count ?? 10; // 0
const withOr = count || 10; // 10
?? сохраняет 0, || заменяет на 10.
Ранее использовался || с дополнительными проверками. Например:
const safeCount = (count !== null && count !== undefined) ? count : 10;
Этот код более длинный и менее наглядный.
Путаница между ?? и ||. Ошибка: применение ?? для логических условий, где нужно учитывать все ложные значения. Также нельзя использовать ?? вместе с && или || без скобок из-за приоритета операторов.

Ожидание завершения всех промисов с разными исходами

Как дождаться выполнения всех асинхронных операций, даже если некоторые завершаются ошибкой?

Метод Promise.allSettled возвращает массив результатов каждого промиса: статус и значение/причину. В отличие от Promise.all, не отклоняется при первом отказе.
const promises = [fetch(url1), fetch(url2)];
Promise.allSettled(promises).then(results => {
  results.forEach(r => console.log(r.status, r.value || r.reason));
});
Ранее требовалось вручную оборачивать каждый промис в catch и возвращать результат. Например:
const wrapped = promises.map(p => p.then(v => ({status: 'fulfilled', value: v}),
                                       r => ({status: 'rejected', reason: r})));
Promise.all(wrapped).then(...);
Это более сложно.
Без всесторонней обработки можно забыть, что allSettled не прекращает выполнение других промисов. Типичная ошибка: путаница с порядком результатов - порядок соответствует исходному массиву.

Глобальный объект в любой среде

Как получить ссылку на глобальный объект (window, global, self) в любом окружении?

Свойство globalThis возвращает глобальный объект в зависимости от среды выполнения.
console.log(globalThis); // в браузере Window, в Node.js global
Раньше использовались разные пути: window, self, global с проверкой typeof. Например:
const globalObj = typeof window !== 'undefined' ? window : (typeof global !== 'undefined' ? global : self);
Этот код громоздкий и не учитывает все окружения.
В строгом режиме глобальный объект может быть undefined. Также globalThis недоступен в старых браузерах (IE11), требуется полифилл.

Работа с большими целыми числами

Как безопасно работать с числами, превышающими 2^53 - 1?

BigInt позволяет представлять целые числа произвольной точности, добавляя суффикс n или вызовом BigInt().
const big = 123456789012345678901234567890n;
const another = BigInt('12345678901234567890');
console.log(big + another); // вычислит без потери точности
Раньше использовались библиотеки сторонних разработчиков, либо выполнялась потеря точности при стандартных числах. Например, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 (true).
BigInt нельзя смешивать с Number без явного преобразования. Ошибка TypeError: Cannot mix BigInt and other types. Также нет поддержки Math функций, округления.

Расширенные примеры применения возможностей JS 11

Комбинирование опциональной цепочки и объединения с null

Пример получения значения из конфигурации с запасным вариантом:

Пример
const config = { api: { timeout: null } };
const timeout = config?.api?.timeout ?? 3000;
console.log(timeout); // 3000, так как timeout равен null
Результат: 3000. Если бы timeout был 0, результат остался бы 0 благодаря ??.

Динамическое обращение к свойству с переменной:

Пример
const key = 'speed';
const value = settings?.effects?.[key]?.value ?? 'default';
Если settings.effects.speed.value отсутствует, возвращается 'default'.

Применение Promise.allSettled с разными типами запросов

Обработка результатов нескольких запросов с разными стратегиями:

Пример
const urls = ['/api/users', '/api/posts', '/invalid'];
const fetchPromises = urls.map(url => fetch(url).then(res => res.json()));
Promise.allSettled(fetchPromises).then(results => {
  const successful = results.filter(r => r.status === 'fulfilled').map(r => r.value);
  const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
  console.log('Успешные:', successful);
  console.log('Ошибки:', failed);
});
В консоль выводятся отдельно успешные ответы и ошибки, программа не падает.

Использование globalThis в полифиллах

Создание универсальной функции, работающей в браузере и Node.js:

Пример
if (!globalThis.fetch) {
  // подгрузка полифилла
  const fetch = require('node-fetch');
  globalThis.fetch = fetch;
}
После этого можно использовать fetch в любом окружении.

BigInt в арифметике и сравнении

Преобразование BigInt в строку и обратно:

Пример
const huge = 1n << 100n;
console.log(huge.toString()); // '1267650600228229401496703205376'
const parsed = BigInt('1267650600228229401496703205376');
console.log(parsed === huge); // true
Строковое представление без потери точности.

Сравнение BigInt и Number через приведение:

Пример
const big = 5n;
const num = 5;
console.log(big == num); // true (нестрогое равенство)
console.log(big === num); // false (разные типы)
Нестрогое равенство может давать неожиданные результаты, но для BigInt и Number оно работает.

Ошибка при смешивании типов в математических операциях:

Пример
const a = 2n;
const b = 3;
// a + b; // TypeError: Cannot mix BigInt and other types
const sum = a + BigInt(b);
console.log(sum); // 5n
Необходимо явное преобразование.

Использование import.meta в модулях ES

Получение метаинформации о текущем модуле:

Пример
// module.js
console.log(import.meta.url); // URL текущего файла
Выводит полный URL.

Это позволяет динамически загружать ресурсы относительно модуля.

JavaScript версия 11 - comments

En
Js 11 (javascript)