> Как реализовать глубокое клонирование объекта в JavaScript? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: МТГ Бизнес решения, EPAM

Стек: JavaScript

> Пример ответа

Короткий ответ

Глубокое клонирование в JavaScript - создание независимой копии объекта со всеми вложенными структурами. Для простых случаев подходит structuredClone() или JSON.parse(JSON.stringify(obj)), но последний не работает с функциями, undefined, Symbol, циклическими ссылками. Для production используйте structuredClone() или библиотеки вроде Lodash (_.cloneDeep). Ручная реализация требует рекурсивного обхода с проверкой типов и обработкой особых случаев.

Подробное объяснение

Глубокое клонирование отличается от поверхностного тем, что создает независимые копии всех вложенных объектов и массивов. В JavaScript есть несколько подходов:

  • structuredClone() - современный нативный метод, поддерживает большинство типов (Date, Map, Set, ArrayBuffer), но не функции и DOM-узлы
  • JSON.parse(JSON.stringify(obj)) - простой, но теряет функции, undefined, Symbol, специальные объекты, не работает с циклическими ссылками
  • Ручная рекурсивная реализация - полный контроль, но требует обработки edge cases
  • Библиотеки (Lodash, Ramda) - проверенные решения для сложных случаев

Ключевые проблемы при реализации: циклические ссылки (бесконечная рекурсия), специальные объекты (Date, RegExp, Map, Set), функции, прототипы, геттеры/сеттеры, WeakMap/WeakSet.

На практике

Для большинства задач в современном фронтенде используйте structuredClone() - он нативный, быстрый и покрывает 95% случаев. Если нужно клонировать функции или специфические объекты, применяйте Lodash _.cloneDeep. JSON-подход подходит только для данных, которые гарантированно сериализуются (например, ответы API). Ручную реализацию пишите, когда важна производительность на специфических структурах или нужен тонкий контроль над процессом.

Пример кода

JAVASCRIPT
// Нативный способ (рекомендуемый)
const original = {
name: 'test',
date: new Date(),
nested: { a: 1 },
map: new Map([['key', 'value']])
};
const cloned = structuredClone(original);
// JSON-подход (ограниченный)
const jsonClone = JSON.parse(JSON.stringify(original));
// Ручная реализация с поддержкой циклических ссылок
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);
if (obj instanceof Map) {
const clone = new Map();
hash.set(obj, clone);
obj.forEach((value, key) => clone.set(key, deepClone(value, hash)));
return clone;
}
if (obj instanceof Set) {
const clone = new Set();
hash.set(obj, clone);
obj.forEach(value => clone.add(deepClone(value, hash)));
return clone;
}
const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));
hash.set(obj, clone);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
return clone;
}

Как отвечать на собеседовании

Начните с упоминания structuredClone() как современного стандарта, затем объясните ограничения JSON-подхода. Покажите понимание проблем: циклические ссылки, потеря типов, производительность. Упомяните, что для production-кода предпочтительнее использовать проверенные библиотеки. Если пишете ручную реализацию, обязательно обработайте циклические ссылки через WeakMap и специальные типы. Завершите рекомендацией выбирать метод под конкретную задачу.

Что проверяет интервьюер

  • Понимание разницы между поверхностным и глубоким копированием
  • Знание нативных возможностей JavaScript (structuredClone, WeakMap)
  • Осведомленность о подводных камнях (циклические ссылки, потеря типов)
  • Умение писать рекурсивные алгоритмы с обработкой edge cases
  • Практический опыт выбора инструмента под задачу

Типичные ошибки

  • Использование JSON.parse(JSON.stringify()) для объектов с функциями или undefined
  • Игнорирование циклических ссылок в ручной реализации (приводит к stack overflow)
  • Забывание про специальные типы: Date, RegExp, Map, Set
  • Копирование прототипа через Object.create() или его потеря
  • Неправильная обработка массивов (клонирование как объектов с числовыми ключами)
  • Использование for...in без проверки hasOwnProperty (захват свойств прототипа)

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью