Зʼявився новий офіційний реліз JavaScript ECMAScript 2023, також відомий як ECMAScript 14. Зміни в основному є вдосконаленнями, а не чимось радикальним. InfoWorld зробив огляд, що нового в JavaScript у 2023 році.
Перш ніж заглиблюватися в деталі нової версії, варто поговорити про специфікацію ECMAScript. Ви завжди можете знайти останню версію специфікації ECMAScript, розміщену на https://tc39.es/ecma262/. Якщо ви хочете переглянути специфікацію в певному році, то можете додати це до URL-адреси. Наприклад, специфікація цього року розміщена за адресою: https://tc39.es/ecma262/2023/.
Специфікація ECMAScript – це документ, який слугує як основним довідником для розробників і викладачів, так і офіційною технічною специфікацією для розробників двигуна JavaScript.
Інша річ, яку слід знати про специфікацію, це те, що це дійсно живий документ, який зростає в інтерактивному режимі, коли мова використовується на практиці. Часто нова функція додається до офіційної специфікації після того, як вона була неофіційно прийнята спільнотою користувачів. Ми можемо побачити це, наприклад, із синтаксисом shebang цього року. Після кодифікації й стандартизації функції специфікація слугує новою стабільною основою для подальших інновацій цієї функції.
Іноді специфікація ECMAScript представляє новаторські ідеї. Прикладом є прийняття синтаксису async/await, на який вплинув C#.
А тепер подивімося на нові функції, представлені в JavaScript у 2023 році.
Array.prototype.toSorted
Почнемо з нового методу масиву toSorted().
toSorted має таку саму сигнатуру, що й Array.prototype.sort(), але створює новий масив замість того, щоб працювати над самим масивом. Ось новий метод масиву в лістингу 1.
Лістинг 1. sort() versus toSorted()
let arr = [5,4,2,3,1]
arr === arr.sort(); // true - [1, 2, 3, 4, 5]
arr === arr.toSorted(); // false - [1, 2, 3, 4, 5]
toSorted() подібно до sort() приймає єдиний необов’язковий аргумент – функцію порівняння. Наприклад, ми можемо використовувати toSorted() для створення нового масиву в порядку спадання, як у лістингу 2.
Лістинг 2. Використання функції comparator
const numbers = [10, 5, 2, 7, 3, 9, 1, 6, 4];
const sortedNumbers = numbers.toSorted((a, b) => {
return b - a;
});
console.log(sortedNumbers); // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Зазначимо також, що toSorted() можна застосувати до масивів об’єктів. У такому випадку ви повинні надати функцію порівняння, яка використовує дані про об’єкти, оскільки для об’єктів немає природного порядку. Приклад можна побачити у лістингу 3.
Лістинг 3. toSorted() з об’єктами
// Comparing objects
const objects = [{ name: "John", age: 30 }, { name: "Jane", age: 25 }, { name: "Bill", age: 40 }, { name: "Mary", age: 20 }];
const sortedObjects = objects.toSorted((a, b) => {
return a.name.localeCompare(b.name);
});
console.log(sortedObjects);
//[{"name":"Bill","age":40},{"name":"Jane","age":25},
{"name":"John","age":30},{"name":"Mary","age":20}]
Лістинг 3 сортує об’єкти за полем імені.
Більшість Array методів також існують на TypedArray, за винятком випадків, де це вказано.
Array.prototype.toReversed
Як toSorted() і sort(), toReversed() є родичем-дублювачем reverse(). У лістингу 4 є кілька швидких прикладів використання toReversed() включно із застосуванням його до об’єктів з функцією порівняння.
Лістинг 4. toReversed()
["a","b","c","d","e"].toReversed(); // ['e', 'd', 'c', 'b', 'a']
Array.prototype.with
Новий метод with() дає змогу змінювати один елемент на основі його індексу та повертати новий масив. Отже, якщо ви знаєте індекс і нове значення, цей метод робить це дуже легко. Зауважте, що with() – це copying companion до set(). У лістингу 5 наведено простий приклад.
Лістинг 5. Заміна елемента на with()
const arr4 = ["I", "am", "the", "Walrus"];
// Replace the string "Walrus" with "Octopus".
const newArr4 = arr4.with(3, "Ape Man");
console.log(newArr4);
Array.prototype.findLast
Метод findLast() дає змогу отримати останній екземпляр відповідного елемента з масиву. Якщо відповідний елемент не знайдено, він повертає undefined. Простий приклад наведено в лістингу 6, де ми отримуємо останнє парне число з масиву.
Лістинг 6. Знайти останнє парне число за допомогою findLast()
const arr = [54, 34, 55, 75, 98, 77];
const lastEvenIndex = arr.findLast((element) => {
return element % 2 === 0;
});
console.log(lastEvenIndex); // 98
findLast() також підтримує передачу «thisArg» для встановлення контексту. Тобто другий аргумент повідомить функції першого аргументу, до чого буде відноситися ключове слово this. Ви можете побачити це в дії у лістингу 7, де ми використовуємо спеціальний об’єкт, щоб знайти перший елемент, який рівномірно ділиться на 5.
Лістинг 7. Використання thisArg
const arr6 = [54, 34, 55, 75, 98, 77];
const myObject = {testCase: 5};
const lastEvenIndex = arr5.findLast((element) => {
return element % myObject.testCase === 0;
}, myObject);
console.log(lastEvenIndex); // 75
Array.prototype.findLastIndex
findLastIndex() працює так само як і findLast(), за винятком того, що він дає вам індекс відповідного елемента замість самого елемента. Наприклад, лістинг 8 показує, як знайти індекс останнього елемента, який рівномірно ділиться на 6.
Лістинг 8. Знайдіть індекс елемента за допомогою findLastIndex()
const arr = [54, 34, 55, 75, 98, 77];
arr.findLastIndex(x => x % 6 === 0); // 0
Array.prototype.toSpliced
Наразі всі методи, які ми описали, також застосовуються до TypedArray. Останній новий метод масиву, toSpliced(), існує лише на Array. Метод toSpliced() є версією splice() – знайомого «швейцарського ножа» для обробки масивів JavaScript.
Скажімо, у нас є масив кольорів і нам потрібно вставити пару нових (рожевий і блакитний) посередині. Ви можете побачити це в лістингу 9. Пам’ятайте, що це створює новий масив, а не змінює оригінальний.
Лістинг 9. toSpliced() у дії
const arr = ["red", "orange", "yellow", "green", "blue", "purple"]; const
newArr = arr.toSpliced(2, 1, "pink", "cyan"); console.log(newArr);
// ["red", "orange", "pink", "cyan", "green", "blue", "purple"] console.log(newArr[3]);
// 'cyan' console.log(arr[3]);
// ‘green’
Офіційна підтримка
Shebang – це старомодна умовна команда Unix з хештегом, за якою йде знак оклику: #! (де «bang» означає «!»). З давніх часів коментар у заголовку файлу, що починається з #!, повідомляє оболонці, що це виконуваний сценарій і який двигун використовувати для його виконання. Наприклад, лістинг 10 – типовий сценарій bash.
Лістинг 10. Shebang на сценарії bash: hello.sh
#!/bin/bash
echo "Hello, world!"
Ви можете запустити файл, як у лістингу 10, безпосередньо за допомогою ./hello.sh.
Ви можете зробити подібне з JavaScript, як показано в лістингу 11.
Лістинг 11. Shebang в JS: hello.js
#!/usr/bin/env node
console.log("Hello, world!");
Лістинг 11 повідомляє операційну систему використовувати програму node для виконання цього сценарію. Тепер ви можете просто ввести ./hello.js для його запуску. Без #! це б не спрацювало.
Підтримка shebang – це одне з оновлень можливостей у специфікації, яке вже було впроваджено та неофіційно прийнято у багатьох контекстах.
Символи як ключі у слабких колекціях
Останньою новою функцією в ECMAScript 14 є розширення того, що можна використовувати як ключі у слабких колекціях.
Слабкі колекції є трохи езотеричними порівняно з повсякденним використанням JavaScript. Слабкого посилання самого по собі недостатньо, щоб уникнути утилізації цільового посилання алгоритмом збирання сміття (ось чому це слабке посилання).
Ви можете дізнатися більше про слабкі посилання і про те, коли вони зручні, тут. За цим покликанням також є хороше обговорення.
ES14 дає змогу використовувати більшість символів як ключі в колекції, тоді як раніше ви могли використовувати лише об’єкт. Ось де ви можете дізнатися більше, що таке символ.
Нова функція значно полегшує використання слабких посилань у колекціях, наприклад WeakMap, спрощуючи обмеження на те, що можна використовувати як ключі. Простий приклад показано в лістингу 12.
Лістинг 12. Використання символу як ключа на WeakMap
var map = new WeakMap(); // create a weak map
function useSymbol(symbol){
doSomethingWith(symbol);
var called = map.get(symbol) || 0;
called++; // called one more time
if(called > 2) console.log("Called more than twice");
map.set(symbol, called);
}
let mySymbol = Symbol("FooBar");
useSymbol(mySymbol);
useSymbol(mySymbol);
useSymbol(mySymbol);
delete mySymbol; // No live references are left to mySymbol, so we can count on the garbage collector eliminating the entry in the weakMap when it runs (eventually)
Лістинг 12 змінено з відповіді StackOverflow. У цьому прикладі мета – дати змогу викликати лічильник із зовнішнього абонента та видалити запис карти, коли немає жодних посилань. Сам код не може дізнатися, коли посилання більше не потрібне, і якщо ви використовуєте звичайний Map, то отримаєте витік пам’яті.
Це пояснюється тим, що код зберігатиме посилання навіть після того, як клієнт, який його викликає, більше не потребуватиме цього. У цьому випадку, коли ми використовуємо WeakMap, можна розраховувати на те, що збирання сміття видалить запис карти, коли більше не буде посилань на символ ключа.
Висновок
Попри те, що 2023 рік був відносно тихим для JavaScript, ECMAScript 14 додав деякі корисні функції та підтримав офіційну специфікацію. У наступній версії ми матимемо низку змін, зокрема новий Temporal API для обробки дат і часу.
Раніше ми повідомляли, що російська хакерська група шпигувала за українськими військовими за допомогою JavaScript-коду.