Що приготував нам ES2020

6 хв. читання

З 2015 року, коли вийшла ES6, Ecma International TC39 почала випускати нову версію ECMAScript кожні 12 місяців. Цьогорічна 11-та версія специфікації, ECMAScript 2020, обіцяє бути наповненою фічами, які спростять життя розробників. Якщо ви ще не чули про них, то хутчіш гортайте нижче.

1. Глобальний this

JavaScript вже перестав бути мовою одного браузера. Дедалі популярнішим він стає в бекенді, мобільній розробці, програмуванні мікроконтролерів тощо.

Кожне середовище має власну модель об'єктів та синтаксис для доступу до глобального об'єкта. Це значно ускладнює кросплатформну розробку на JavaScript:

// середовище браузера
console.log(window);

// середовище node.js 
console.log(global);

// середовище воркера
console.log(self);
// ...

Звичайно, ви можете написати власну функцію, котра визначатиме, яку змінну використовувати в тому чи іншому середовищі. З globalThis робити так більше не знадобиться, адже це стандартизований спосіб доступу до this в різних середовищах.

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. Оператор null-об'єднання

На черзі новий інструмент, який полегшить вашу розробку — оператор null-об'єднання. Раніше, щоб надати властивості чи змінній дефолтне значення, ми використовували ||. Тоді, якщо властивість об'єкта чи змінна повертала значення falsy, надавалось перше правдиве значення після ||. Однак такий спосіб мав недолік: він пропускав такі значення, як false, 0, пустий рядок, а це не завжди бажано. Оператор null-об'єднання ?? розв'язує цю проблему.

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

Як бачимо, оператор ?? присвоює значення з правого боку, лише якщо значення з лівого боку null або undefined.

4. Оператор опціональної послідовності

Досі, аби перевірити на null/undefined значення властивості глибоко в ієрархії об'єкта, доводилось перевіряти кожну попередню властивість на null чи undefined:

// Перевіряємо попередні властивості:
const deeplyNestedValue = obj && obj.prop1 && obj.prop1.prop2;
// Перевіряємо чи є елемент в DOM:
const fooInputEl = document.querySelector('input[name=foo]');
const fooValue = fooInputEl && fooInputEl.value;

Оператор опціональної послідовності допомагає провести такі перевірки у більш зручний спосіб. Код вище ми можемо переписати з новим оператором так:

// Перевіряємо попередні властивості:
const deeplyNestedValue = obj?.prop1?.prop2;
// Перевіряємо чи є елемент в DOM:
const fooInputEl = document.querySelector('input[name=foo]');
const fooValue = document.querySelector('input[name=foo]')?.value;

Варто знати

Оператор опціональної послідовності — оператор «раціонального обчислення», тобто він припиняє своє виконання, якщо властивість ліворуч від ?. повертає null чи undefined.

// збільшує x тоді й лише тоді, коли 'a' не null чи undefined
a?.[++x]

І наостанок, оператор опціональної послідовності працює також з функціями:

func?.(...args) // опціональний виклик функції чи методу

5. BigInt

За роботу з числами в JavaScript відповідає тип number. Проблема в тому, що значення цього типу обмежуються 2⁵³. Всі числові значення, що перевищують максимальне для number, поводяться дивно.

const x = Number.MAX_SAFE_INTEGER; // 9007199254740991
const y = x + 1; // 9007199254740992 • дорівнює 2^53
const z = x + 2; // 9007199254740992 • щось пішло не так

Цю проблему розв'яже новий примітивний тип — BigInt, який працюватиме з числами, більшими за 2⁵³. Аби створити змінну типу BigInt додайте символ n в кінець числа:

const aBigInteger = 9007199254740993n;
// Існує також конструктор:
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()

Досі імпорт модулів був статичним та працював лише з рядковими літералами (import module from './module'). Всі імпорти оброблялись до виконання коду, на етапі зв'язування.

Динамічний import(...) працює в рантаймі, тож тепер ми можемо виконати завдання, які досі були неможливі:

  • завантаження мови користувача, а не всіх мов одразу;
  • ліниве завантаження роутів у застосунку (покращує продуктивність);
  • обробка помилок, якщо модуль не знайдено.

Як це працює

// Динамічний import() виконує роль функції, яка повертає проміс. Його можна обробити так: 
// Використовуючи колбеки
import('/module.js')
  .then((module) => {
    // Робота з модулем.
  });
// Використовуючи async / await
async function () {
  let module = await import('/modules.js');
}

Варто звернути увагу на особливості динамічного імпорту:

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

7. String.protype.matchAll

Метод matchAll() повертає ітератор, який перебирає всі збіги з регулярним виразом:

const regexp = RegExp('[a-z]*ball','g');
const str = 'basketball handball pingpong football';
const matches = str.matchAll(regexp);
// Оскільки метод повертає ітератор, перебрати результати можна настпуним чином
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]
// Так можна отримати масив всіх результатів 
let results = [...str.matchAll(regexp)];

Варто знати

Метод match() не повертає конструкції групування при використанні глобального прапора /g. А matchAll(), як бачимо з прикладу, повертає.

Як спробувати нові фічі

Якщо вам хочеться якомога швидше випробувати нові фічі у своєму проєкті, Babel підготував для вас плагіни:

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 6.3K
Приєднався: 7 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація