State of JavaScript 2023, один з найочікуваніших щорічних звітів про розвиток JavaScript, опублікував оновлену інформацію про актуальні фічі. У цій статті ми детально розглянемо рейтинг фіч, що використовуються найбільше, а також приклади їх застосування.
Фічі синтаксису
Оператор об’єднання з null
1 місце. Nullish Coalescing. Проголосувало 80% людей.
Оператор об’єднання з null ??
дозволяє легко задавати значення, якщо змінна дорівнює null або undefined, на відміну від оператора ||
, який оперує тільки falsy значеннями. Це зручно при роботі з необов'язковими значеннями та для уникнення помилок.
const unknown1 = null;
const foo = unknown1 ?? 'default';
console.log(foo); // 'default'
const unknown2 = 0;
const bar = unknown2 ?? 42;
console.log(bar); // 0
Динамічний імпорт
2 місце. Dynamic Import. Проголосувало 62% людей.
Динамічний імпорт дозволяє завантажувати модулі асинхронно, коли вони дійсно потрібні. Це допомагає оптимізувати перфоманс вашого додатку, завантажуючи код лише за потребою, що зменшує початковий розмір бандлу.
let myModule;
if (typeof window === "undefined") {
myModule = await import("module-used-on-server");
} else {
myModule = await import("module-used-in-browser");
}
Приватні поля
3 місце. Private Fields. Проголосувало 35% людей.
Для створення приватного поля в класах, потрібно додати префікс #
до назви і це дозволить створювати властивості, доступ до яких можливий лише всередині класу. Це забезпечує кращу інкапсуляцію даних та захист від доступу ззовні класу.
class MyClass {
#privateField = 10;
getPrivateField() {
return this.#privateField;
}
}
const instance = new MyClass();
console.log(instance.getPrivateField()); // 10
console.log(instance.#privateField);
// SyntaxError: Private field '#privateField' must be declared in an enclosing class
Майте на увазі, що в DevTools приватні поля все ще доступні для зручного дебагінгу.
Логічне присвоєння
4 місце. Logical Assignment. Проголосував 31% людей.
Логічні оператори присвоєння &&=
, ||=
та ??=
дозволяють скоротити код, комбінуючи логічні оператори з присвоєнням. Це робить код простішим та зрозумілішим.
let settings;
function emptyIfNotExist() {
settings ||= {};
// Замість
// if (!settings) {
// settings = {};
// }
}
function removeIfExist() {
settings &&= null;
// Замість
// if (settings) {
// settings = null;
// }
}
function setNullIfNotDefined() {
settings ??= null;
// Замість
// if (settings === null || settings === undefined) {
// settings = null;
// }
}
Простими словами, до одного з операторів &&
, ||
або ??
можна додати в кінець =
, тим самим записавши нове значення в змінну, що перевіряється.
Граматика Hashbang (Shebang)
5 місце. Hashbang Grammar. Проголосувало 22% людей.
Hashbang #!
дозволяє вказати інтерпретатор скрипту безпосередньо в коді JavaScript, що корисно для написання скриптів, які виконуються у середовищі Node.js.
#!/usr/bin/env node
console.log('Hello, world!');
Детальніше про Hashbang на Wiki.
error.cause
6 місце. Проголосувало 16% людей.
Ця функція дозволяє вказувати причину для помилок, що полегшує відстеження ланцюга викликів помилок та робить дебагінг більш простим та інформативним.
try {
connectToDatabase();
} catch (err) {
throw new Error('Connecting to database failed.', { cause: err });
}
Фічі string
string.replaceAll()
1 місце. Проголосувало 73% людей.
Метод replaceAll()
дозволяє замінювати всі збіги всередині рядка. Це значно спрощує операції пошуку та заміни в тексті.
const str = 'foo bar foo';
const newStr = str.replaceAll('foo', 'baz');
console.log(newStr); // 'baz bar baz'
string.matchAll()
2 місце. Проголосувало 44% людей.
Метод matchAll()
повертає ітератор, що містить всі збіги регулярного виразу в рядку. Це корисно для обробки складних шаблонів та отримання всіх результатів одночасно.
const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';
const array = [...str.matchAll(regexp)];
console.log(array);
// Output: Array [
// ['test1', 'e', 'st1', '1'],
// ['test2', 'e', 'st2', '2'],
// ]
Індекси відповідності Regexp
3 місце. Regexp Match Indices. Проголосувало 24% людей.
Індекси відповідності регулярних виразів додаються за допомогою d
прапора та дозволяють отримати позиції всіх збігів, що допомагає більш точно обробляти текст.
const str1 = "foo bar foo";
const regex1 = /foo/dg;
console.log(regex1.hasIndices); // true
console.log(regex1.exec(str1).indices[0]); // [0, 3]
console.log(regex1.exec(str1).indices[0]); // [8, 11]
const str2 = "foo bar foo";
const regex2 = /foo/;
console.log(regex2.hasIndices); // false
console.log(regex2.exec(str2).indices); // undefined
Фічі array
array.findLast()
1 місце. Проголосувало 30% людей.
Метод findLast()
працює так само, як і find
, але починає пошук з кінця масиву та повертає останній елемент, який задовольняє умову.
const arr = [1, 2, 3, 4, 5];
const found = arr.findLast(element => element % 2 === 0);
console.log(found); // 4
array.toSorted()
, array.toReversed()
та array.toSpliced()
2, 3 та 4 місце. Проголосувало 30%, 26% та 16% людей відповідно.
Ці три методи є стовідсотковими копіями своїх оригінальних методів sort
, reverse
та splice
з єдиною відмінністю - вони не мутують оригінальний масив, а створюють новий.
const arr = [3, 1, 4, 1, 5];
const sorted = arr.toSorted();
console.log(sorted); // [1, 1, 3, 4, 5]
console.log(arr); // [3, 1, 4, 1, 5]
array.with()
5 місце. Проголосувало 11% людей.
Метод with()
повертає новий масив з одним зміненим елементом, що дозволяє легко оновлювати дані без мутації оригінального масиву.
const arr = [1, 2, 3, 4, 5];
console.log(arr.with(2, 6)); // [1, 2, 6, 4, 5]
Фічі асинхронності
Top-level await
1 місце. Проголосувало 74% людей.
Оператор await
на верхньому рівні дозволяє використовувати асинхронний код безпосередньо в модулях без обгортки в асинхронні функції, що робить код більш зрозумілим та прямолінійним.
// top-level-await.mjs
const data = await fetchData();
console.log(data);
Promise.any()
2 місце. Проголосувало 43% людей.
Метод Promise.any()
повертає перший успішно виконаний проміс з масиву. Це корисно для сценаріїв, де достатньо першого успішного результату, ігноруючи всі відхилені проміси.
const promise1 = Promise.reject('Error 1');
const promise2 = new Promise(
(resolve) => setTimeout(resolve, 100, 'Result 2'),
);
const promise3 = new Promise(
(resolve) => setTimeout(resolve, 200, 'Result 3'),
);
const value = await Promise.any([promise1, promise2, promise3]);
console.log(value); // 'Result 2'
Promise.allSettled()
3 місце. Проголосувало 43% людей.
Метод Promise.allSettled()
повертає усі результати промісів, незалежно від того, були вони успішні чи ні. Це дозволяє обробляти всі завершення промісів одночасно, не перериваючи роботу через помилки.
const promise1 = Promise.resolve('Result 1');
const promise2 = Promise.reject('Error 2');
const promise3 = Promise.resolve('Result 3');
const results = await Promise.allSettled([promise1, promise2, promise3])
results.forEach((result) => {
console.log(result.status, result.value || result.reason)
});
// fulfilled Result 1
// rejected Error 2
// fulfilled Result 3
Статистика взята зі State Of JS Features.