← Назад к вопросам
Deep clone объекта
1.7 Middle🔥 171 комментариев
#Node.js и JavaScript#Алгоритмы и структуры данных
Условие
Напишите функцию deepClone(obj), которая создает глубокую копию объекта:
function deepClone(obj) {
// Ваш код
}
const original = {
name: "John",
age: 30,
address: {
city: "Moscow",
zip: 123456
},
hobbies: ["reading", "coding"]
};
const cloned = deepClone(original);
cloned.address.city = "London";
cloned.hobbies.push("gaming");
console.log(original.address.city); // "Moscow" (не изменился)
console.log(original.hobbies); // ["reading", "coding"] (не изменился)
Что проверяется
- Рекурсия
- Работа с объектами и массивами
- Обработка разных типов данных (Date, RegExp и т.д.)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Deep Clone объекта
Базовая реализация
function deepClone<T>(obj: T): T {
// Примитивные типы и null
if (obj === null || typeof obj !== 'object') {
return obj;
}
// Date
if (obj instanceof Date) {
return new Date(obj.getTime()) as unknown as T;
}
// RegExp
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags) as unknown as T;
}
// Массивы
if (Array.isArray(obj)) {
const clonedArray: any[] = [];
for (let i = 0; i < obj.length; i++) {
clonedArray[i] = deepClone(obj[i]);
}
return clonedArray as T;
}
// Объекты
if (obj instanceof Object) {
const clonedObject: any = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObject[key] = deepClone((obj as any)[key]);
}
}
return clonedObject as T;
}
return obj;
}
С обработкой циклических ссылок (WeakMap)
function deepClone<T>(obj: T, visited = new WeakMap<any, any>()): T {
// Примитивные типы
if (obj === null || typeof obj !== 'object') {
return obj;
}
// Циклические ссылки
if (visited.has(obj)) {
return visited.get(obj);
}
let cloned: any;
// Date
if (obj instanceof Date) {
cloned = new Date(obj.getTime());
visited.set(obj, cloned);
return cloned as T;
}
// RegExp
if (obj instanceof RegExp) {
cloned = new RegExp(obj.source, obj.flags);
visited.set(obj, cloned);
return cloned as T;
}
// Map
if (obj instanceof Map) {
cloned = new Map();
visited.set(obj, cloned);
obj.forEach((value, key) => {
cloned.set(deepClone(key, visited), deepClone(value, visited));
});
return cloned as T;
}
// Set
if (obj instanceof Set) {
cloned = new Set();
visited.set(obj, cloned);
obj.forEach((value) => {
cloned.add(deepClone(value, visited));
});
return cloned as T;
}
// Массивы
if (Array.isArray(obj)) {
cloned = [];
visited.set(obj, cloned);
for (let i = 0; i < obj.length; i++) {
cloned[i] = deepClone(obj[i], visited);
}
return cloned as T;
}
// Объекты
if (obj instanceof Object) {
cloned = Object.create(Object.getPrototypeOf(obj));
visited.set(obj, cloned);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone((obj as any)[key], visited);
}
}
return cloned as T;
}
return obj;
}
Примеры
// Пример 1: Простой объект
const original = {
name: "John",
age: 30,
address: {
city: "Moscow",
zip: 123456
},
hobbies: ["reading", "coding"]
};
const cloned = deepClone(original);
cloned.address.city = "London";
cloned.hobbies.push("gaming");
console.log(original.address.city); // "Moscow"
console.log(original.hobbies); // ["reading", "coding"]
// Пример 2: С Date и RegExp
const withDate = {
created: new Date(),
pattern: /test/gi
};
const clonedDate = deepClone(withDate);
console.log(clonedDate.created instanceof Date); // true
// Пример 3: С циклическими ссылками
const circular = { name: 'node' };
circular.self = circular; // циклическая ссылка
const clonedCircular = deepClone(circular);
console.log(clonedCircular.self === clonedCircular); // true
Ключевые моменты
1. Рекурсия
- Обрабатываем каждый уровень вложенности
- Базовый случай: примитивные типы
2. instanceof проверки
- Date, RegExp, Array имеют свои конструкторы
- Массивы — это тип Object, поэтому Array.isArray() важен
3. WeakMap для циклических ссылок
- Хранит соответствие оригинальных объектов и их копий
- Автоматически удаляется из памяти
- Предотвращает бесконечную рекурсию
4. hasOwnProperty
- Пропускаем унаследованные свойства
- Копируем только собственные свойства
Vs structuredClone (Modern)
// Встроенный метод (Node.js 17+)
const cloned = structuredClone(original);
// Плюсы: встроенный, быстрый
// Минусы: не клонирует функции, классы с методами
Тестирование
test('deepClone простого объекта', () => {
const obj = { a: 1, b: { c: 2 } };
const cloned = deepClone(obj);
cloned.b.c = 999;
expect(obj.b.c).toBe(2);
});
test('deepClone массива', () => {
const arr = [1, [2, 3], 4];
const cloned = deepClone(arr);
cloned[1][0] = 999;
expect(arr[1][0]).toBe(2);
});
test('deepClone Date', () => {
const date = new Date();
const cloned = deepClone({ date });
expect(cloned.date instanceof Date).toBe(true);
expect(cloned.date).not.toBe(date);
});
test('deepClone циклических ссылок', () => {
const obj = { a: 1 };
obj.self = obj;
const cloned = deepClone(obj);
expect(cloned.self === cloned).toBe(true);
});