Поверхневе копіювання проти глибокого копіювання в JavaScript
Поверхневе та Глибоке Копіювання
При копіюванні об'єктів у JavaScript важливо розуміти різницю між поверхневим та глибоким копіюванням, щоб уникнути несподіваних помилок.
Проблема
const original = { name: "Alice", scores: [90, 85, 92] };
const copy = original; // ❌ Це не копія — лише інша ссилка!
copy.name = "Bob";
console.log(original.name); // "Bob" — оригінал також змінено!Поверхневе Копіювання
Поверхневе копіювання створює новий об'єкт з копіями властивостей верхнього рівня. Однак вкладені об'єкти все ще спільні (однакові ссилки).
Методи для Поверхневого Копіювання
const obj = { a: 1, nested: { b: 2 } };
// Оператор розподілу
const copy1 = { ...obj };
// Object.assign
const copy2 = Object.assign({}, obj);
// Методи масиву
const arr = [1, [2, 3]];
const arrCopy1 = [...arr];
const arrCopy2 = arr.slice();
const arrCopy3 = Array.from(arr);Обмеження Поверхневого Копіювання
const original = { name: "Alice", address: { city: "Kyiv" } };
const shallow = { ...original };
shallow.name = "Bob"; // ✅ Незалежний
shallow.address.city = "Lviv"; // ❌ Змінює оригінал!
console.log(original.address.city); // "Lviv"Глибоке Копіювання
Глибоке копіювання створює повністю незалежну копію — всі вкладені об'єкти також копіюються.
1. structuredClone() (Сучасний, Рекомендується)
const original = {
name: "Alice",
scores: [90, 85],
address: { city: "Kyiv" },
date: new Date()
};
const deep = structuredClone(original);
deep.address.city = "Lviv";
console.log(original.address.city); // "Kyiv" ✅ Незалежний!Підтримує: об'єкти, масиви, Date, Map, Set, RegExp, ArrayBuffer тощо.
Не підтримує: функції, DOM-елементи, об'єкти помилок, символи як ключі.
2. JSON.parse(JSON.stringify())
const deep = JSON.parse(JSON.stringify(original));Обмеження:
- ❌ Втрачає
undefined, функції,Symbol - ❌ Перетворює
Dateна рядок - ❌ Не обробляє кругові посилання
- ❌ Втрачає
Map,Set,RegExp
3. Користувацька Рекурсивна Функція
function deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (Array.isArray(obj)) return obj.map(deepClone);
const clone = {};
for (const key of Object.keys(obj)) {
clone[key] = deepClone(obj[key]);
}
return clone;
}4. Бібліотеки
// Lodash
import { cloneDeep } from 'lodash';
const deep = cloneDeep(original);Таблиця Порівняння
| Метод | Тип | Функції | Дата | Кругові |
|---|---|---|---|---|
{ ...obj } | Поверхневе | ✅ | ✅ | Н/Д |
Object.assign() | Поверхневе | ✅ | ✅ | Н/Д |
structuredClone() | Глибоке | ❌ | ✅ | ✅ |
JSON.parse/stringify | Глибоке | ❌ | ❌ | ❌ |
lodash.cloneDeep() | Глибоке | ✅ | ✅ | ✅ |
Важливо:
Використовуйте structuredClone() для глибокого копіювання в сучасних середовищах (доступно у всіх браузерах з 2022 року та Node.js 17+). Використовуйте оператор розподілу ({ ...obj }) для поверхневих копій. Уникайте JSON-серіалізації для складних об'єктів з датами, функціями або круговими посиланнями.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.