GlobalThis, необязательное связывание, частные поля в классах, нулевой оператор объединения и многое другое.

Как вы, возможно, знаете, начиная с ES6 в 2015 году, каждый год TC39 из Ecma International выпускает новую версию ECMAScript. ECMAScript 2020 - это 11-е издание спецификации языка ECMAScript.

Эта новая итерация включает в себя ряд новых функций - давайте рассмотрим их!

1. «globalThis»

Язык JavaScript сейчас довольно популярен и может использоваться в самых разных средах - в веб-браузерах, конечно, но JavaScript также можно запускать на стороне сервера, на смартфонах, роботизированно и т. Д.

Каждая среда имеет собственную объектную модель и синтаксис для доступа к глобальному объекту. Из-за этого может быть сложно написать код JavaScript, который работает в нескольких средах:

// browser environment
console.log(window);

// node.js environment
console.log(global);

// Service worker environment
console.log(self);
// ...

Конечно, можно стандартизировать его для нескольких платформ, написав функцию, которая проверяет текущую среду, но это больше не понадобится!

Свойство globalThis теперь является стандартным способом согласованного доступа к глобальному объекту в разных средах.

2. «Promise.allSettled ()»

Метод Promise.allSettled() возвращает обещание, которое разрешается после того, как все данные обещания были разрешены или отклонены, с массивом объектов, каждый из которых описывает результат каждого обещания через свойство status. Это упрощает их фильтрацию.

const p1 = new Promise((res) => res("🍕"));
const p2 = new Promise((res, rej) => rej("🍍"));
const p3 = new Promise((res) => res("🍺"));
Promise.allSettled([p1, p2, p3]).then(data => console.log(data));
// [
//   { status: "fulfilled", value: "🍕" },
//   { status: "rejected", value: "🍍" },
//   { status: "fulfilled", value: "🍺" },
// ]

3. Оператор нулевого слияния

Оператор объединения с нулевым значением - это новый инструмент в вашем наборе инструментов, когда вы пытаетесь предоставить значение по умолчанию при выполнении доступа к свойствам. Он отличается от оператора или, обозначенного знаком || между двумя значениями, тем, как он обрабатывает нулевые значения.

Давайте посмотрим, как это работает, сравнив два оператора:

const test = {
  null: null,
  number: 0,
  string: '',
  boolean: false
};
const undefinedValue = test.dog || "Cat"; // "Cat"
const undefinedValue = test.dog ?? "Cat"; // "Cat"
const nullValue = test.null || "Default"; // "Default"
const nullValue2 = test.null ?? "Default"; // "Default"
const numberValue = test.number || 1; // 1
const numberValue2 = test.number ?? 1; // 0
const stringValue = test.string || "Hello"; // "Hello"
const stringValue2 = test.string ?? "Hello"; // ""
const booleanValue = test.boolean || true; // true
const booleanValue2 = test.boolean ?? true; // false

Как видите, нулевой оператор coalsceing выбирает значение в правой части только тогда, когда выражение в левой части ?? равно null или undefined.

4. Необязательный оператор цепочки

До сих пор при поиске значения свойства, которое глубоко вложено в объект, или при использовании API, возвращающего либо объект, либо null / undefined, часто приходилось действовать следующим образом для проверки промежуточных значений:

// Checking for intermediate nodes:
const deeplyNestedValue = obj && obj.prop1 && obj.prop1.prop2;
// Checking if the node exists in the DOM:
const fooInputEl = document.querySelector('input[name=foo]');
const fooValue = fooInputEl && fooInputEl.value;

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

// Checking for intermediate nodes:
const deeplyNestedValue = obj?.prop1?.prop2;
// Checking if the node exists in the DOM:
const fooValue = document.querySelector('input[name=foo]')?.value;

Полезно знать

Необязательный оператор цепочки - это короткое замыкание, что означает, что он прекращает оценку строки, если левая часть ?. оценивается как null или undefined:

// x is incremented if and only if 'a' is not null or undefined
a?.[++x]

И последнее: необязательный оператор цепочки также работает с функциями.

func?.(...args) // optional function or method call

5. «BigInt»

У нас уже есть Number для представления чисел в JavaScript. Проблема в том, что наибольшее число 2⁵³. Кроме того, это уже не совсем надежно.

const x = Number.MAX_SAFE_INTEGER; // 9007199254740991
const y = x + 1; // 9007199254740992 • equal to 2^53
const z = x + 2; // 9007199254740992 • well, it's broken

Вы поняли: BigInt - это новый примитив, обеспечивающий способ представления числа больше 2 ⁵³. Он создается добавлением n в конец целого числа:

const aBigInteger = 9007199254740993n;
// There is also a constructor:
const evenBigger = BigInt(9007199254740994); // 9007199254740994n
const fromString = BigInt("9007199254740995"); // 9007199254740995n

Полезно знать

BigInt в основном ведет себя так же, как number, но их нельзя использовать вместе в операции:

let sum = 1n + 2, multiplication = 1n * 2;
// TypeError: Cannot mix BigInt and other types, use explicit conversions

BigInt можно преобразовать в Number с помощью конструктора Number(), но в некоторых случаях вы можете потерять точность. По этой причине рекомендуется использовать BigInt только тогда, когда в вашем коде ожидаются большие значения.

Number(900719925474099267n); // 900719925474099300 • 🤷‍♂️

6. «динамический импорт ()»

Текущая форма импорта модулей import module from './module' является статической и принимает только строковый литерал. Он также работает только перед запуском как процесс связывания.

Динамический import(...) позволяет разработчикам динамически загружать части приложения JavaScript во время выполнения. Это дает несколько преимуществ, которые сейчас import не поддерживает:

  • Загружать язык пользователя вместо того, чтобы загружать их все
  • Ленивая загрузка маршрутов вашего приложения (повышение производительности)
  • Может справиться с ошибкой, если модуль не найден

Как это работает?

// Used as a function, import() returns a promise that can be handled the 2 usuals ways:
// Using callback
import('/module.js')
  .then((module) => {
    // Do something with the module.
  });
// Using async / await
async function () {
  let module = await import('/modules.js');
}

Вот заметные отличия от обычного объявления import:

  • import() можно использовать из скриптов, а не только из модулей
  • import() может произойти где угодно на любом уровне и не поднимается
  • import() принимает произвольные строки (с определенными во время выполнения шаблонными строками, как показано здесь), а не только статические строковые литералы.

7. «String.protype.matchAll»

Метод matchAll() возвращает итератор всех результатов, соответствующих строке и регулярному выражению (RegExp), и работает следующим образом:

const regexp = RegExp('[a-z]*ball','g');
const str = 'basketball handball pingpong football';
const matches = str.matchAll(regexp);
// Since it is an iterator, you can loop trought results this way:
let match = matches.next();
while (!match.done) {
 console.log(match.value);
 match = matches.next();
}
// ["basketball", index: 0, input: "basketb...", groups: undefined]
// ["handball", index: 11, input: "basketb...", groups: undefined]
// ["football", index: 29, input: "basketb...", groups: undefined]
// One can also get an array of all results
let results = [...str.matchAll(regexp)];

Полезно знать

Хотя метод match() не возвращает группы захвата при использовании с глобальным флагом /g, matchAll() это делает.

Заключение

На этот год все!

В Babel уже есть плагины почти для всех этих функций. Если вам не терпится использовать их в своих проектах, вот ссылки:

Спасибо за прочтение!