Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Деструктуризація в JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Destructuring assignment** (деструктуризація): синтаксис JavaScript (ES6), який витягує значення з масивів або властивості об'єктів в окремі змінні за один крок. ```javascript const [a, b] = [1, 2]; const { name } = { name: 'Alice' }; console.log(a, name); // 1 'Alice' ``` **Ключове:** значення за замовчуванням спрацьовує тільки при `undefined`, не при `null` чи `0`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Destructuring assignment** (деструктуризація): синтаксис JavaScript, який витягує значення з масивів або властивості об'єктів в окремі змінні за один крок, замість кількох рядків ручного присвоєння. ## Теорія ### TL;DR - Уяви що розпаковуєш посилку з підписаними комірками: береш тільки потрібне і кладеш в підписані кошики - Деструктуризація масивів працює за **позицією**, а об'єктів, за **назвою ключа** - Значення за замовчуванням спрацьовує тільки коли значення `undefined`, не `null` чи `0` - Rest (`...`) збирає решту елементів і завжди має стояти останнім - Використовуй коли витягуєш 2+ значення; для одного значення точкова нотація читабельніша ### Швидкий приклад ```javascript // Масив: за позицією const [first, second] = [10, 20, 30]; console.log(first); // 10 console.log(second); // 20 // Об'єкт: за назвою ключа const user = { name: 'Alice', age: 25 }; const { name, age } = user; console.log(name); // 'Alice' console.log(age); // 25 ``` Двигун читає зліва направо: для масивів використовує індекси, для об'єктів шукає властивість через `GetOwnProperty`. Скомпільований код еквівалентний ручному присвоєнню, тому різниці у продуктивності немає. ### Коли використовувати - **API-відповіді** з кількома полями: `const { data, error } = await fetchUser(id)` - **Параметри функції** з об'єкта: `function greet({ name, role = 'user' }) {}` - **Обмін змінними**: `[a, b] = [b, a]` без тимчасової змінної - **React hooks**: `const [count, setCount] = useState(0)` - **Іменовані імпорти**: `import { useState, useEffect } from 'react'` Для одного значення краще пропусти. `user.name` читабельніше ніж `const { name } = user`, якщо тобі потрібне тільки воно. ### Патерни для масивів **Пропуск елементів** через порожній слот: ```javascript const [first, , third] = [1, 2, 3]; console.log(third); // 3 ``` **Rest** збирає решту: ```javascript const [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4] ``` **Значення за замовчуванням** спрацьовує тільки при `undefined`: ```javascript const [x = 5] = [0]; console.log(x); // 0 (не 5, бо 0 не є undefined) ``` ### Патерни для об'єктів **Перейменування** через двокрапку після ключа: ```javascript const { name: userName } = { name: 'Alice' }; console.log(userName); // 'Alice' ``` **Вкладені** патерни потребують вкладеного синтаксису: ```javascript const { address: { city } } = { address: { city: 'Kyiv' } }; console.log(city); // 'Kyiv' ``` Якщо `address` є `undefined`, це кине TypeError. Додай значення за замовчуванням або перевір через optional chaining (`?.`) перед деструктуризацією. **Rest** для об'єктів збирає всі залишкові ключі: ```javascript const { id, ...rest } = { id: 1, name: 'Alice', age: 25 }; console.log(rest); // { name: 'Alice', age: 25 } ``` ### Типові помилки **Вкладена деструктуризація кидає TypeError на undefined.** ```javascript const data = {}; const { user: { name } } = data; // TypeError: Cannot read properties of undefined ``` Виправлення: `const { user: { name } = {} } = data` або `data.user?.name`. **Rest не може стояти не в кінці.** ```javascript const [...rest, last] = [1, 2, 3]; // SyntaxError ``` Rest має бути останнім. `[first, ...rest]` працює, `[...rest, last]` не скомпілюється. **Неправильна назва ключа при перейменуванні.** ```javascript const { userName } = { name: 'Alice' }; console.log(userName); // undefined ``` `userName` шукає ключ буквально з назвою `userName`. Для перейменування потрібен синтаксис `{ name: userName }`. **Значення за замовчуванням не замінює `null`.** ```javascript const [x = 5] = [null]; console.log(x); // null (замовчування спрацьовує тільки для undefined) ``` ### Де зустрічається в реальних проектах - **React**: `const [value, setValue] = useState('')`, пропси компонента `function Button({ onClick, label })` - **Express/Node.js**: `const { id } = req.params`, `const { page = 1 } = req.query` - **Redux Toolkit**: `const { type, payload: { id } } = action` - **SWR/React Query**: `const { data, error } = useSWR('/api/user')` ### Питання на співбесіді **Q:** Що виведе `const [x = 1] = [0]`? **A:** `0`. Значення за замовчуванням спрацьовує тільки коли значення `undefined`. Нуль є визначеним значенням. **Q:** Що станеться якщо деструктурувати ключ якого немає в об'єкті? **A:** Отримаєш `undefined`. Помилки не буде, якщо тільки не спробуєш деструктурувати властивість цього `undefined`. **Q:** Як по-різному поводяться `null` і `undefined` зі значеннями за замовчуванням? **A:** Тільки `undefined` активує значення за замовчуванням. `null` проходить як є. Це часте джерело помилок на співбесідах. **Q:** Можна деструктурувати повернуте значення функції? **A:** Так. `const [success, data] = await fetchData()` працює коли функція повертає масив. **Q:** (Senior) Як V8 компілює `const { x } = obj`? **A:** Емітує перевірку `GetOwnProperty` для ключа `x` на `obj`, потім присвоює результат новій прив'язці. Патерни масивів компілюються до індексованого доступу (`arr[0]`, `arr[1]`). Rest використовує перебір властивостей або `slice`. Байткод еквівалентний ручному присвоєнню. ## Приклади ### Базовий: масиви та об'єкти ```javascript const coords = [10, 20, 30]; const [x, y] = coords; console.log(x, y); // 10 20 const product = { title: 'Keyboard', price: 99, stock: 5 }; const { title, price } = product; console.log(title, price); // 'Keyboard' 99 ``` Деструктуризація масиву бере за індексом, об'єкта за ключем. Якщо ключ не існує, отримаєш `undefined`, а не помилку. ### Реальний сценарій: параметри функції з замовчуваннями ```javascript // Форма очікуваного вводу видна прямо в сигнатурі function handleRequest({ params: { id }, query: { role = 'viewer', page = 1 } }) { console.log(id, role, page); } handleRequest({ params: { id: '42' }, query: { role: 'admin' } }); // '42', 'admin', 1 ``` Такий патерн зустрічається в React-компонентах, Express-хендлерах і Redux-редюсерах. На практиці це найкорисніше застосування деструктуризації: бачиш що функція очікує не заходячи в тіло. Це скорочує час на розуміння незнайомого коду.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.