Вивчай

Об'єкти — частина 2

JavaScript destructuring — розпаковка подарунка з окремо загорнутими частинами всерединіJavaScript destructuring — розпаковка подарунка з окремо загорнутими частинами всередині

У минулому уроці ми вивчили основи об'єктів. Тепер розберемо сучасні способи роботи з ними — деструктуризацію, spread оператор та optional chaining. Ці інструменти використовуються в кожному сучасному JavaScript та React проєкті.


Destructuring — деструктуризація об'єктів

Замість витягувати властивості по одній, можна "розпакувати" їх одразу:

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

// Без деструктуризації
const name = user.name;
const age = user.age;

// З деструктуризацією
const { name, age, city } = user;
console.log(name); // "Олексій"
console.log(age);  // 25
console.log(city); // "Київ"

Перейменування

const user = { name: "Олексій", age: 25 };

const { name: userName, age: userAge } = user;
console.log(userName); // "Олексій"
console.log(userAge);  // 25

Значення за замовчуванням

const user = { name: "Олексій" };

const { name, age = 0, role = "user" } = user;
console.log(age);  // 0 (значення за замовчуванням)
console.log(role); // "user"

Деструктуризація в параметрах функції

Дуже поширений патерн:

// Без деструктуризації
function greet(user) {
  console.log(`Привіт, ${user.name}! Тобі ${user.age} років.`);
}

// З деструктуризацією — чистіше
function greet({ name, age }) {
  console.log(`Привіт, ${name}! Тобі ${age} років.`);
}

greet({ name: "Олексій", age: 25 });
Порада

Деструктуризація в параметрах — must-know для React. Кожен компонент React отримує props саме так: function Button({ label, onClick }).


Деструктуризація масивів

Працює за позицією (на відміну від об'єктів — за ім'ям):

const colors = ["червоний", "зелений", "синій"];

const [first, second, third] = colors;
console.log(first);  // "червоний"
console.log(second); // "зелений"

// Пропуск елементів
const [, , last] = colors;
console.log(last); // "синій"

// Swap двох змінних (без тимчасової!)
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1

Spread оператор для об'єктів

... "розпаковує" об'єкт:

Копіювання

const original = { name: "Олексій", age: 25 };
const copy = { ...original };

copy.age = 30;
console.log(original.age); // 25 — оригінал не змінився
console.log(copy.age);     // 30

Злиття об'єктів

const defaults = { theme: "light", language: "uk", fontSize: 16 };
const userSettings = { theme: "dark", fontSize: 18 };

const settings = { ...defaults, ...userSettings };
console.log(settings);
// { theme: "dark", language: "uk", fontSize: 18 }
// userSettings перезаписує defaults

Додавання/оновлення властивостей

const user = { name: "Олексій", age: 25 };

// Додати нову властивість
const userWithCity = { ...user, city: "Київ" };
// { name: "Олексій", age: 25, city: "Київ" }

// Оновити існуючу
const olderUser = { ...user, age: 26 };
// { name: "Олексій", age: 26 }
Порада

Spread — ключовий патерн для імутабельності (immutability). Замість мутації user.age = 26 створюєш новий об'єкт { ...user, age: 26 }. Чому це важливо — детально в наступному уроці. А в React та Redux це обов'язковий підхід.


Rest оператор для об'єктів

"Збирає" залишкові властивості:

const user = { name: "Олексій", age: 25, city: "Київ", email: "alex@test.com" };

const { name, ...rest } = user;
console.log(name); // "Олексій"
console.log(rest); // { age: 25, city: "Київ", email: "alex@test.com" }

Корисно для видалення властивості без delete:

const { password, ...safeUser } = userData;
// safeUser — все, крім password

Optional Chaining — ?.

Безпечний доступ до вкладених властивостей:

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

// Без optional chaining — потенційна помилка
// console.log(user.contacts.email); // ❌ TypeError!

// З optional chaining
console.log(user.contacts?.email);       // undefined (не помилка)
console.log(user.address?.city);         // "Київ"
console.log(user.address?.street?.name); // undefined

Nullish Coalescing — ??

Значення за замовчуванням, якщо null або undefined:

const user = { name: "Олексій", age: 0 };

// || повертає default для будь-якого falsy (0, "")
console.log(user.age || 18);      // 18 ❌ (0 — falsy!)

// ?? повертає default тільки для null/undefined
console.log(user.age ?? 18);      // 0 ✅
console.log(user.email ?? "N/A"); // "N/A" (undefined)
Порада

?. + ?? — потужна комбінація: user.address?.city ?? "Невідомо" — безпечно дістати значення або повернути default.


Практика

// 1. Злиття налаштувань
function mergeSettings(defaults, custom) {
  return { ...defaults, ...custom };
}
const config = mergeSettings(
  { theme: "light", lang: "uk", debug: false },
  { theme: "dark", debug: true }
);
console.log(config); // { theme: "dark", lang: "uk", debug: true }

// 2. Витягнути дані з API-відповіді
const apiResponse = {
  status: 200,
  data: {
    user: { id: 1, name: "Олексій", role: "admin" },
    token: "abc123",
  },
};

const { data: { user: { name, role }, token } } = apiResponse;
console.log(name, role, token); // "Олексій" "admin" "abc123"

// 3. Безпечне отримання
function getUserCity(user) {
  return user?.address?.city ?? "Місто не вказано";
}

console.log(getUserCity({ address: { city: "Київ" } })); // "Київ"
console.log(getUserCity({}));                              // "Місто не вказано"
console.log(getUserCity(null));                            // "Місто не вказано"

Підсумок

  • Destructuring: const { name, age } = user — розпаковка об'єктів
  • Destructuring масивів: const [a, b] = array — за позицією
  • Spread: { ...obj } — копіювання, злиття, immutable оновлення
  • Rest: const { a, ...rest } = obj — збирає залишок
  • Optional chaining: obj?.prop?.nested — безпечний доступ
  • Nullish coalescing: value ?? default — default тільки для null/undefined

Що далі?

У наступному уроці розберемо мутабельність та імутабельність — чому spread створює "нову версію", а не змінює оригінал, і чому це критично для React.

Інфо

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