Недавно опциональный доступ к аттрибутам (Optional Chaining) и значение по умолчанию для атрибутов (Nullish Coalescing) перешли на последний, четвёртый этап процесса TC39.
На практике это означает, что эти и другие нововведения станут частью стандарта JavaScript уже в этом, 2020 году. Их мы и рассмотрим в этой статье.
Отслеживать поддержку браузерами можно здесь («2020 features») — прим. перев.
String.prototype.matchAll
Использование «липких» (sticky) или глобальных регулярных выражений, когда надо захватить несколько групп на одной строке, может оказаться нетривиальным.
String.prototype.match не возвращает захваченные группы при наличии глобального флага, а без него можно получить только первое полное соответствие шаблону и его группы.
Пример:
let regexp = /t(e)(st(d?))/g;
let str = 'test1test2';
const results = str.match(regexp);
console.log(results);
Результат с флагом «g»
Результат без флага «g»
Использование String.prototype.matchAll гарантирует, что будут возвращены все соответствия и их группы.
Пример:
let regexp = /t(e)(st(d?))/g;
let str = 'test1test2';
let array = [...str.matchAll(regexp)];
console.log(array);
Результат:
BigInt
До появления BigInt наибольшее значение, представляемое Number, было равно 2⁵³-1 (MAX_SAFE_INTEGER). Теперь в JavaScript будет примитив, способный превзойти лимит.
Создать BigInt можно добавив 'n' к числу или используя функцию BigInt().
Пример:
let bigInt = 4n
console.log(bigInt * bigInt)
- BigInt не эквивалентен Number, но может быть приведён к последнему.
- При выполнении операций вроде деления, результат будет округлён до 0.
- Нельзя использовать с Number без приведения типов.
Попытка сложить BigInt с числом...
let bigInt = 4n + 2
console.log(bigInt)
… приводит к исключению:
globalThis
Доступ к глобальным объектам в мире JavaScript всегда был головной болью. Вы должны быть знакомы со специфическим синтаксисом для окружения, что создаёт лишние трудности при написании переносимого кода и приводит к необходимости использовать что-то вроде getGlobal.
Пример:
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('no global object found');
};
var globals = getGlobal();
С появлением globalThis можно перестать думать об окружении и получать глобальные объекты унифицировано.
Пример:
globalThis.someFunction = () => 'hello'
console.log(globalThis.someFunction())
Promise.allSettled
Допустим, у вас есть несколько промисов, и вы хотите что-то сделать после их завершения (неважно, успешного или нет). Promise.allSettled нужен именно для этого.
Пример:
const fulfilledPromise = Promise.resolve("success");
const rejectedPromise = Promise.reject("error")
const promises = [fulfilledPromise, rejectedPromise];
Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result)));
Результат:
Dynamic Import
Хотите загрузить модуль во время выполнения, в зависимости от определенного условия? Теперь это можно будет сделать без сторонних библиотек.
Достаточно вызвать функцию import, которая вернёт промис.
Пример:
import("some_module")
.then(module => {
module.doSomething();
})
.catch(err => {
console.error(err.message);
});
В отличие от статического импорта, где нужно указывать имя модуля явно, при динамическом импорте вы можете, например, передать в функцию шаблон.
Пример с использованием шаблона:
import(`${some_module}.js`)
.then(module => {
module.doSomething();
})
.catch(err => {
console.error(err.message);
});
Nullish coalescing
Когда нужно получить атрибут или значение по умолчанию, если он null или undefined, мы обычно используем оператор ‘||’.
До Nullish coalescing:
const response = someResponse.properties.mayBeUndefined || 'Response';
Представьте, однако, что атрибут имеет «ложное» значение.
Проблема использования ‘||’:
const someResponse = {properties: { mayBeUndefined: ''}}
const response = someResponse.properties.mayBeUndefined || 'Response';
console.log(response)
Результат:
Это нежелательное поведение. В данном случае нам нужно было значение атрибута, а не значение по умолчанию.
С Nullish coalescing этой проблемы не будет. Значение по умолчанию будет возвращено только для атрибутов null или undefined.
Использование Nullish coalescing:
const someResponse = {properties: { mayBeUndefined: ''}}
const response = someResponse.properties.mayBeUndefined ?? 'Response';
console.log(response)
Результат:
Optional Chaining
Чтобы получить доступ к под-атрибуту, нам нужно убедиться, что атрибут выше существует. Пока что существование каждого из над-атрибутов нужно проверять вручную.
До Optional Chaining:
const someObj = {
property: 'prop',
otherProperty: {
name: 'prop2'
}
};
const property = someObj.NotOtherProperty ? someObj.NotOtherProperty.name: undefined;
console.log(property);
С появлением Optional Chaining, можно будет использовать оператор ‘?.’ для опционального доступа к под-атрибутам. Код ниже эквивалентен коду выше.
Использование Optional Chaining:
const someObj = {
property: 'prop',
otherProperty: {
name: 'prop2'
}
};
const property = someObj.NotOtherProperty?.name;
console.log(property);
Optional Chaining делает код гораздо чище, особенно, если атрибутов в строке много.
Заключение
Вы можете попробовать запустить примеры из статьи в консоли: некоторые из них уже реализованы в последних версиях браузеров, другие, вероятно, будут внедрены очень скоро. Так или иначе, к возможностям из статьи уже можно начинать относиться как к части языка образца 2020 года.
Автор: germn