Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы создания клона объекта в JavaScript
Клонирование объектов — важная задача, поскольку присваивание по ссылке в JavaScript приводит к тому, что изменения в «копии» влияют на оригинал. Существует несколько подходов, каждый со своими особенностями.
📌 Поверхностное клонирование (Shallow Copy)
Создаёт новый объект, но вложенные объекты/массивы копируются по ссылке.
1. Spread оператор (...) (современный стандарт)
const original = { a: 1, b: { c: 2 } };
const clone = { ...original };
console.log(clone.a); // 1
console.log(clone.b === original.b); // true (вложенный объект — ссылка)
2. Object.assign()
const original = { x: 10, y: { z: 20 } };
const clone = Object.assign({}, original);
3. Цикл for...in
function shallowClone(obj) {
const clone = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = obj[key];
}
}
return clone;
}
📌 Глубокое клонирование (Deep Copy)
Полностью независимая копия со всеми вложенными структурами.
1. JSON методы (ограниченный способ)
const original = {
name: "Test",
data: { values: [1, 2, 3] },
date: new Date()
};
const clone = JSON.parse(JSON.stringify(original));
console.log(clone.data !== original.data); // true
console.log(typeof clone.date); // "string" (дата стала строкой!)
Недостатки: теряются функции, undefined, Symbol, Map/Set, классовые инстансы, циклические ссылки вызывают ошибку.
2. Рекурсивная функция
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
// Для Symbol ключей
const symbolKeys = Object.getOwnPropertySymbols(obj);
for (let symKey of symbolKeys) {
clone[symKey] = deepClone(obj[symKey], hash);
}
return clone;
}
3. Использование structuredClone() (современный API)
const original = {
name: "Object",
nested: { array: [1, 2, 3] },
date: new Date()
};
const clone = structuredClone(original);
console.log(clone.nested !== original.nested); // true
console.log(clone.date instanceof Date); // true
Преимущества: поддерживает больше типов данных, обрабатывает циклические ссылки, но не клонирует функции, DOM-узлы, прототипы.
📌 Специализированные библиотеки
- Lodash:
_.cloneDeep(value) - jQuery:
$.extend(true, {}, original)
📋 Сравнение методов
| Метод | Глубина | Функции | Циклические ссылки | Производительность |
|---|---|---|---|---|
| Spread оператор | Поверхностная | Сохраняет | Неприменимо | Высокая |
| JSON методы | Глубокая | Теряет | Ошибка | Средняя |
| Рекурсия | Глубокая | Сохраняет | Обрабатывает | Зависит от глубины |
| structuredClone() | Глубокая | Теряет | Обрабатывает | Высокая |
🎯 Рекомендации по выбору
- Для простых объектов без вложенностей — используйте
spreadилиObject.assign() - Для полного глубокого клонирования — предпочтительнее
structuredClone()в поддерживаемых средах - Для сложных случаев с функциями/классами — пишите кастомную рекурсивную функцию или используйте проверенную библиотеку
- Всегда проверяйте наличие циклических ссылок в данных
Ключевой принцип: выбирайте метод в зависимости от структуры данных и требований к производительности. Для большинства повседневных задач structuredClone() и spread оператора достаточно, но важно понимать их ограничения, особенно при работе с state management (Redux, MobX) или immutable подходами.