Вивчай

ES6+ — частина 2

JavaScript ES6+ optional chaining — садова стежка з каменів-сходинок над ставком де деякі шляхи зникають у туманіJavaScript ES6+ optional chaining — садова стежка з каменів-сходинок над ставком де деякі шляхи зникають у тумані

Продовжуємо вивчати сучасний JavaScript. У цьому уроці — фічі з ES2019-ES2023, які роблять код безпечнішим та лаконічнішим.


Optional Chaining — ?.

Ми вже зустрічали ?. у Block 4. Поглибимо знання:

const user = {
  name: "Олексій",
  address: { city: "Київ" },
};

// Безпечний доступ до вкладених властивостей
console.log(user.address?.city);         // "Київ"
console.log(user.contacts?.email);       // undefined (замість TypeError)

// Для методів
console.log(user.getName?.());           // undefined (метод не існує)

// Для масивів
const arr = [1, 2, 3];
console.log(arr?.[5]);                   // undefined

Ланцюжки

const response = {
  data: {
    users: [
      { name: "Олексій", settings: { theme: "dark" } },
    ],
  },
};

const theme = response?.data?.users?.[0]?.settings?.theme;
console.log(theme); // "dark"

// Без optional chaining — купа перевірок:
const theme2 = response && response.data && response.data.users
  && response.data.users[0] && response.data.users[0].settings
  && response.data.users[0].settings.theme;

Nullish Coalescing — ??

Повертає правий операнд тільки якщо лівий null або undefined:

const count = 0;
const name = "";

// || замінює ВСІ falsy (0, "", false)
console.log(count || 10);   // 10 ❌ (0 — валідне значення!)
console.log(name || "Гість"); // "Гість" ❌

// ?? замінює тільки null/undefined
console.log(count ?? 10);   // 0 ✅
console.log(name ?? "Гість"); // "" ✅

console.log(null ?? "default");      // "default"
console.log(undefined ?? "default"); // "default"

Комбінація ?. та ??

function getUserTheme(user) {
  return user?.settings?.theme ?? "light";
}

console.log(getUserTheme({ settings: { theme: "dark" } })); // "dark"
console.log(getUserTheme({}));                                // "light"
console.log(getUserTheme(null));                              // "light"

Logical Assignment Operators

ES2021 додав скорочення для логічних операцій з присвоєнням:

||= (OR assignment)

let title = "";
title ||= "Без назви";  // якщо falsy → присвоїти
console.log(title); // "Без назви"

// Еквівалент: title = title || "Без назви"

??= (Nullish assignment)

let config = { theme: null, fontSize: 0 };

config.theme ??= "light";     // null → присвоїти
config.fontSize ??= 16;       // 0 — не null, не присвоювати

console.log(config); // { theme: "light", fontSize: 0 }

&&= (AND assignment)

let user = { name: "Олексій", loggedIn: true };

user.loggedIn &&= false; // якщо truthy → присвоїти
console.log(user.loggedIn); // false
Порада

??= — найкорисніший з трьох. Ідеальний для встановлення значень за замовчуванням: options.timeout ??= 5000.


Корисні методи масивів (ES2019+)

Array.flat() — розгортання вкладених масивів

const nested = [1, [2, 3], [4, [5, 6]]];

console.log(nested.flat());    // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2));   // [1, 2, 3, 4, 5, 6]
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6]

Array.flatMap() — map + flat

const sentences = ["Привіт світ", "Як справи"];
const words = sentences.flatMap((s) => s.split(" "));
console.log(words); // ["Привіт", "світ", "Як", "справи"]

at() — доступ за індексом (ES2022)

const arr = [10, 20, 30, 40, 50];

console.log(arr.at(0));   // 10
console.log(arr.at(-1));  // 50 (останній!)
console.log(arr.at(-2));  // 40

// Замість arr[arr.length - 1]

Object.groupBy() (ES2024)

const students = [
  { name: "Олексій", grade: "A" },
  { name: "Марія", grade: "B" },
  { name: "Іван", grade: "A" },
  { name: "Анна", grade: "B" },
];

const grouped = Object.groupBy(students, (s) => s.grade);
// { A: [{name:"Олексій",...}, {name:"Іван",...}], B: [...] }

Object.fromEntries()

Зворотна операція до Object.entries():

// entries → object
const entries = [["name", "Олексій"], ["age", 25]];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: "Олексій", age: 25 }

// Практичний приклад: трансформація об'єкта
const prices = { apple: 10, banana: 15, cherry: 25 };

const doubled = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 2])
);
console.log(doubled); // { apple: 20, banana: 30, cherry: 50 }

structuredClone() — глибока копія

const original = {
  name: "Олексій",
  hobbies: ["JS", "React"],
  address: { city: "Київ" },
};

const clone = structuredClone(original);
clone.hobbies.push("TypeScript");
clone.address.city = "Львів";

console.log(original.hobbies);     // ["JS", "React"] — не змінився
console.log(original.address.city); // "Київ" — не змінився
Порада

structuredClone() — сучасна заміна JSON.parse(JSON.stringify(obj)). Підтримує Date, Map, Set, RegExp та інші типи, які JSON не підтримує.


Підсумок

  • ?. — безпечний доступ (замість ланцюжка &&)
  • ?? — default тільки для null/undefined (краще за || для 0 та "")
  • ??= — присвоїти якщо null/undefined
  • .at(-1) — останній елемент масиву
  • .flat() — розгортання вкладених масивів
  • Object.fromEntries() — масив пар → об'єкт
  • structuredClone() — глибока копія

Що далі?

У наступному уроці вивчимо Promises — основу асинхронного JavaScript.

Інфо

Корисні посилання: