Доброго времени суток, друзья. На дворе 2К20 год. Окунемся в текущие новшества JavaScript. В этой статье мы рассмотрим следующие темы:
— BigInt
— Dynamic import
— GlobalThis
— Private Class Variables
— Promise.allSettled()
— Nullish Coalescing Operator
— Optional Chaining Operator
— Numeric Separators
— String.protype.matchAll
— import.meta
— export * as nameModule from «module»
Теперь мы разберем каждую из них более подробно.
BigInt
Начнем наши новшества с чисел. В JavaScript для работы с числами до недавнего времени использовался 64-битный формат IEEE-754, однако данные числа ограничены по длине (2 в степени 53).
Пример:
let num = Number.MAX_SAFE_INTEGER
console.log(num) // 9007199254740991
num + 1 // 9007199254740992
num + 2 // 9007199254740992 ???
BigInt это примитивный тип, который предназначен решить даную проблему. Для того, чтобы получить BigInt можно воспользоваться двумя способами:
1. Передать в число в BigInt конструктор;
2. Дописать n в конце числа;
typeof 99 // ‘number’
typeof 99n // ‘bigint’
Решим выше рассмотренный пример с использованием нового типа:
let bigInt = BigIng(num) + BigIng(2)
console.log(bigInt) // 9007199254740993n
Вот теперь данное вычисление корректно.
Dynamic import
Благодаря динамическим импортам можно более удобно вызывать загрузку модуля в нужном месте в виде промиса.
Пример:
import(‘./module.js’)
.then(module => {
//
})
.catch(err => {
//
});
или с использованием async/await
Пример:
(async function() {
const module = await import(‘./module.js’)
//
})();
GlobalThis
Часто для доступа к глобальному объекту нужно использовать определенный синтаксис для разных сред исполнения.
— для Node.js это global
— для Worker это self
— для браузера это window, который мы получаем через this.
Раньше, если приложение исполняется в нескольких средах, необходимо было написать дополнительный код с условиями.
Пример:
let global = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
С нововведением GlobalThis все эти проблемы отошли на второй план:
GlobalThis == this // true
Private Class Variables
После появления в js синтаксического сахара в виде классов некоторые возможности ООП языков не были реализованы, но наступило время приватных полей (модификаторов доступа). Был добавлен символ # (аналог в других языках private), который позволяет изменить доступ к свойству или методу класса.
Пример:
class User{
#name = ‘value’
get name() {
return this.#name
}
}
new User().name // SyntaxError
Так же появились статические свойства.
Пример:
class User{
static age = 999
}
console.log(User.age) // 999
Promise.allSettled()
Среди ряда уже давно используемых комбинаторов (Promise.all, Promise.race, Promise.any) появился новый allSettled. Promise.allSettled возвращает промис с массивом состояний промисов. Главное условие выполнения данного промиса является выполнение всех исходных промисов, а именно все промисы должны быть завершены, вне зависимости от их статуса.
Пример:
let urls = [
‘https://api/test',
‘https://api/test2'
];
Promise.allSettled(urls.map(url => fetch(url)))
.then(results => {
console.log('Все запросы отработали, можно выполнить действие …’)
});
Nullish Coalescing Operator
При обращение к свойству, значение которого null или undefined, следует получить дефолтное значение. Для такого популярного кейса часто использовался оператор ||, но возникал ряд связанных с ним проблем, для решения которых был добавлен оператор ??
Пример:
let foo = '' || 'string'
console.log(foo) // default string
let foo = '' ?? 'default string';
console.log(foo); // ''
let foo = null ?? 'string';
console.log(foo); // string
Optional Chaining Operator
Данная фича пришла из TypeScript. На мой взгляд, она очень полезна при работе с большой вложенностью у объектов. Часто бывает, что объект имеет несколько уровней вложенности и при обращении к дальнему вложенному ключу, может произойти ошибка из-за его отсутствия. В качестве решения создавалась условная проверка для каждого такого свойства. Оператор опциональных цепочек (?) позволяет легко решить эту задачу без написания лишнего кода.
Пример:
const obj = { body: { a: 1, b: 2 } }
// old
const value = obj.body && obj.body.a
// new
const value = obj.body?.a
Numeric Separators
Еще со времен написания кода на Java, C# меня раздражало, что в js из-за отсутствия разделителей, нет возможности более ясно визуализировать большие числа. Во многих языках эту роль играют сепараторы, вот и настало время этой фичи в js.
Давайте напишем такое условие с использованием числового сепаратора: 50000 == 50_000 // true. Помните, что это просто синтаксический сахар и выражение: 50000 == 50_0_0_0 // true
также истинно. Это фича только для вашего визуального восприятия, она не является технической и не несет какой-либо функциональности.
String.protype.matchAll
MatchAll — метод объекта string, позволяющий получить итератор при совпадении регулярного выражения со строкой. Главная его фишка это получение в массиве индексов с текущими совпадениями. Старый метод match, выполняющий аналогичную работу, возвращает лишь массив найденных значений (при условии добавления в регулярку g ).
Пример:
let reg = /value (\d+)/g;
let str = 'value 2 value 10';
console.log(str.match(reg));
// ["value 2", "value 10"]
let matches;
while ((matches = reg.exec(str)) !== null) {
console.log(matches);
}
// ["value 2", "2", index: 0, input: "value 2 value 10", groups: undefined]
// ["value 10", "10", index: 8, input: "value 2 value 10", groups: undefined]
import.meta
Для работы с метаданными модулей появился объект import.meta.
Пример получения мета данных файла .jpg:
const res = await fetch(new URL("./image.jpg", import.meta.url));
const blob = await res.blob();
const size = import.meta.scriptElement.dataset.size || 300;
Еще пример:
<script type="module" src="module.js"></script>
console.log(import.meta); // { url: "file:///app/module.js" }
Мы загружаем .js модуль через тег script и в результате в исполняемом файле получаем метаданные модуля. К слову, до появления import.meta использовались библиотеки, но речь в данной статье не о них.
export *
Напоследок еще одна новая фича — экспорт всего содержимого из модуля. По сути export * аналогичен импорту всего модуля в обратном направлении.
Пример:
import * as moduleName from "module"
export * as nameModule from "module"
Такая запись дает удобство и экономию в написании кода.
Заключение
Надеюсь данная статья была вам полезна. Мы рассмотрели основные новшества, которые будут нас радовать в ES11. Все эти нововведения в первую очередь дают нам более удобный лаконичный синтаксис для решения наших повседневных задач. Меньше кода — выше эффективность. Учитесь, думайте, пишите код. Удачного кодинга, друзья!
Полезные ссылки:
https://tc39.es/ecma262 — спецификация ECMA-262
Подписывайтесь на наш канал в Telegram и на YouTube для получения самой последней и актуальной информации.
Отлично. И кто же Вам мешает её использовать? Уверяю, ни одно нововведение в движке старый код не порушит. Более того, даже если новый код будет написан с использованием нововведений, он сможет использоваться совместно со старым.