Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Глибока копія об'єкта». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Глибока копія (deep copy), це повністю незалежний об'єкт разом з усіма вкладеними об'єктами й масивами, тому зміни в копії не впливають на оригінал.** Основних способів чотири: вбудований `structuredClone(obj)` (сучасні браузери і Node.js 17+, зберігає `Date`, `Map`, `Set`, але втрачає функції та прототипи), класичний `JSON.parse(JSON.stringify(obj))` (працює всюди, але втрачає функції, `undefined`, `Symbol`, `BigInt`, `Date`, `Map`, `Set`, `RegExp`), `_.cloneDeep(obj)` з lodash (найнадійніший для складних структур) і власна рекурсивна функція (добра для розуміння механіки, але не покриває спеціальні типи). ```javascript const user = { name: 'Alice', address: { city: 'Kyiv' }, tags: ['dev'] }; const clone = structuredClone(user); clone.address.city = 'Lviv'; clone.tags.push('frontend'); console.log(user.address.city); // "Kyiv" console.log(user.tags); // ['dev'] ``` **Ключове:** за замовчуванням беріть `structuredClone(obj)`, а `_.cloneDeep(obj)`, коли потрібна максимальна сумісність і стабільність.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Щоб зробити глибоку копію об'єкта, використовують вбудований `structuredClone(obj)`, а для складних проєктів `_.cloneDeep(obj)` з lodash.** Глибока копія, це повністю незалежний об'єкт, включно з усіма вкладеними об'єктами й масивами, тому зміни в копії не впливають на оригінал. ## Теорія ### TL;DR - Глибока копія відтворює **все дерево** об'єкта, а не лише верхній рівень. - `structuredClone(obj)`, вбудований, сучасний і швидкий, але не копіює функції та прототипи. - `JSON.parse(JSON.stringify(obj))` працює скрізь, але мовчки втрачає багато типів. - `_.cloneDeep(obj)` з lodash, найнадійніший варіант для складних структур. - Власна рекурсивна функція корисна для розуміння механіки, але не покриває `Map`, `Set`, `Date`, `RegExp`. - Практичне правило: `structuredClone()` за замовчуванням, `cloneDeep()`, коли потрібна максимальна сумісність. ### Швидкий приклад ```javascript const user = { name: 'Alice', address: { city: 'Kyiv', zip: 12345 }, tags: ['dev', 'frontend'] }; const clone = structuredClone(user); clone.address.city = 'Lviv'; clone.tags.push('react'); console.log(user.address.city); // "Kyiv" console.log(user.tags); // ['dev', 'frontend'] ``` ## Що таке «глибока копія» **Глибока копія (deep copy)**, це коли створюється **повністю незалежний об'єкт**, включно з усіма **вкладеними об'єктами та масивами**. Зміни в копії **не впливають** на оригінал. Протилежність, це поверхнева копія (`{ ...obj }`, `Object.assign()`), яка копіює лише верхній рівень і залишає вкладені об'єкти спільними посиланнями. ## Спосіб 1: сучасний, `structuredClone()` Найнадійніший і найпростіший метод, доступний в усіх сучасних браузерах і в Node.js 17 та новіших. ```javascript const user = { name: 'Alice', address: { city: 'Kyiv', zip: 12345 }, tags: ['dev', 'frontend'] }; const clone = structuredClone(user); clone.address.city = 'Lviv'; clone.tags.push('react'); console.log(user.address.city); // "Kyiv" console.log(user.tags); // ['dev', 'frontend'] ``` **Переваги:** - копіює **об'єкти, масиви, дати, `Map`, `Set`** та інші структуровані типи; - **безпечний і швидкий**, бо реалізований у рушії. **Обмеження:** - не копіює **функції** та **прототипи** (вони втрачаються); - не підтримує `undefined` як ключ (але підтримує як значення). ## Спосіб 2: через `JSON.parse(JSON.stringify())` Класичний спосіб, який працює скрізь, навіть у старих браузерах: ```javascript const user = { name: 'Alice', address: { city: 'Kyiv' }, tags: ['frontend', 'dev'] }; const clone = JSON.parse(JSON.stringify(user)); clone.address.city = 'Lviv'; console.log(user.address.city); // "Kyiv" ``` **Переваги:** - просто й універсально, без залежностей. **Недоліки:** - втрачає: - функції; - `undefined`, `Symbol`, `BigInt`; - `Date`, `Map`, `Set`, `RegExp` (перетворюються на звичайні об'єкти або рядки). - повільніший на дуже великих об'єктах. ## Спосіб 3: за допомогою lodash (`_.cloneDeep()`) Якщо проєкт великий або використовується TypeScript, це **найнадійніший варіант**. ```javascript import _ from 'lodash'; const clone = _.cloneDeep(user); ``` **Переваги:** - глибоко копіює **будь-які типи даних** (включно з `Date`, `Map`, `Set`, `Buffer` тощо); - працює стабільно в усіх середовищах. **Недолік:** - потребує встановлення бібліотеки: ```bash npm install lodash ``` ## Спосіб 4: ручна рекурсивна копія (для розуміння) Якщо хочете зрозуміти механіку, ось базова реалізація: ```javascript function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (Array.isArray(obj)) { return obj.map(deepClone); } const clone = {}; for (const key in obj) { clone[key] = deepClone(obj[key]); } return clone; } const user = { name: 'Alice', address: { city: 'Kyiv' } }; const clone = deepClone(user); clone.address.city = 'Lviv'; console.log(user.address.city); // "Kyiv" ``` Працює для звичайних об'єктів і масивів, але не для `Map`, `Set`, `Date`, `RegExp` тощо: для цього потрібен lodash або `structuredClone`. ## Підсумкова таблиця | Метод | Підтримка | Копіює вкладені об'єкти | Зберігає типи (`Date`, `Map`, `Set`) | Копіює функції | | --- | --- | --- | --- | --- | | `structuredClone()` | Сучасні браузери, Node.js 17+ | Так | Так | Ні | | `JSON.parse(JSON.stringify())` | Скрізь | Так | Ні | Ні | | `_.cloneDeep()` | Через бібліотеку lodash | Так | Так | Ні | | Рекурсивна функція | Ручна реалізація | Так | Ні | Ні | **В одній фразі:** > Щоб зробити надійну глибоку копію, беріть `structuredClone(obj)`, коли потрібна вбудована функція, і `_.cloneDeep(obj)`, коли проєкт великий і важлива стабільність. ### Типові помилки - **Плутати глибоку копію з поверхневою.** `{ ...obj }` створює новий об'єкт, але вкладені структури залишаються спільними. - **Клонувати через JSON об'єкт із датами.** Після такого клонування `Date` стає рядком, і `clone.createdAt.getTime()` кидає помилку. - **Очікувати методи після клонування.** Ані `structuredClone()`, ані JSON-трюк, ані проста рекурсія не переносять прототип, тому екземпляр класу стає звичайним об'єктом. - **Викликати `structuredClone()` на об'єкті з функцією.** Він кидає `DataCloneError`, а не мовчки пропускає властивість, як JSON. - **Використовувати наївну рекурсію на циклічних структурах.** Без кешу вже скопійованих об'єктів (наприклад, через `WeakMap`) вона зациклиться і переповнить стек. - **Тягнути lodash заради одного виклику в сучасному середовищі.** Там уже є вбудований `structuredClone()`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.