← Назад к вопросам
Глубокое клонирование объекта
2.0 Middle🔥 131 комментариев
#JavaScript Core#Архитектура и паттерны
Условие
Напишите функцию deepClone(obj), которая создаёт глубокую копию объекта, включая все вложенные объекты и массивы.
Требования
-
Функция должна корректно обрабатывать:
- Примитивные значения
- Вложенные объекты
- Массивы (в том числе вложенные)
- null и undefined
- Date объекты
-
Изменения в клоне не должны влиять на оригинал
Пример
const original = {
name: "John",
address: {
city: "Moscow",
coords: [55.75, 37.62]
},
date: new Date("2024-01-01")
};
const clone = deepClone(original);
clone.address.city = "SPb";
console.log(original.address.city); // "Moscow"
console.log(clone.address.city); // "SPb"
Бонус
Обработайте циклические ссылки в объекте.
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Глубокое клонирование объекта
Почему глубокое клонирование важно?
При работе со сложными структурами данных в JavaScript обычное присваивание создаёт ссылку на объект, а не его копию. Изменение значений во вложенных объектах или массивах повлияет на оригинал. Глубокое клонирование создаёт полностью независимую копию, включая все вложенные структуры.
Базовая рекурсивная реализация
function deepClone(obj) {
// Обработка примитивов
if (obj === null || typeof obj !== "object") {
return obj;
}
// Обработка Date
if (obj instanceof Date) {
return new Date(obj.getTime());
}
// Обработка Array
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
// Обработка Object
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
Версия с обработкой циклических ссылок
function deepClone(obj, seen = new WeakMap()) {
// Обработка примитивов
if (obj === null || typeof obj !== "object") {
return obj;
}
// Проверка на циклические ссылки
if (seen.has(obj)) {
return seen.get(obj);
}
// Обработка Date
if (obj instanceof Date) {
return new Date(obj.getTime());
}
// Обработка Array
if (Array.isArray(obj)) {
const cloned = [];
seen.set(obj, cloned);
obj.forEach((item, index) => {
cloned[index] = deepClone(item, seen);
});
return cloned;
}
// Обработка Object
const cloned = {};
seen.set(obj, cloned);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key], seen);
}
}
return cloned;
}
TypeScript версия с расширенной типизацией
function deepClone<T>(obj: T, seen: WeakMap<object, any> = new WeakMap()): T {
// Примитивы
if (obj === null || typeof obj !== "object") {
return obj;
}
// Циклические ссылки
if (seen.has(obj as object)) {
return seen.get(obj as object);
}
// Date
if (obj instanceof Date) {
return new Date((obj as Date).getTime()) as unknown as T;
}
// Array
if (Array.isArray(obj)) {
const cloned: any[] = [];
seen.set(obj, cloned);
obj.forEach((item, index) => {
cloned[index] = deepClone(item, seen);
});
return cloned as unknown as T;
}
// Object
const cloned = {} as T;
seen.set(obj as object, cloned);
(Object.keys(obj) as Array<keyof T>).forEach(key => {
cloned[key] = deepClone((obj as any)[key], seen);
});
return cloned;
}
Примеры использования
// Базовый пример
const user = {
name: "Alice",
profile: { age: 30, city: "Moscow" }
};
const userCopy = deepClone(user);
userCopy.profile.age = 25;
console.log(user.profile.age); // 30
console.log(userCopy.profile.age); // 25
// С датами
const event = {
name: "Conference",
date: new Date("2024-12-01")
};
const eventClone = deepClone(event);
eventClone.date.setMonth(5);
console.log(event.date.getMonth()); // 11
console.log(eventClone.date.getMonth()); // 5
// С циклическими ссылками
const parent = { name: "Parent" };
const child = { name: "Child", parent };
parent.child = child;
const clonedParent = deepClone(parent);
console.log(clonedParent.child.parent === clonedParent); // true
Альтернативные подходы
JSON метод (ограничения):
const clone = JSON.parse(JSON.stringify(obj));
// Проблемы: теряет Date, undefined, функции, Symbol
structuredClone (современный API):
const clone = structuredClone(obj);
// Плюсы: работает в современных браузерах, обрабатывает циклы
// Минусы: не поддерживается в старых браузерах
Ключевые моменты
- WeakMap для циклических ссылок: слабые ссылки позволяют сборщику мусора очищать объекты
- hasOwnProperty: проверяет только собственные свойства, исключая наследованные
- instanceof Date: Date нужно обрабатывать отдельно, так как это объект
- Рекурсия: каждый уровень вложенности обрабатывается функцией рекурсивно
- Производительность: WeakMap хранит ссылки без утечек памяти