← Назад к вопросам

Как сделать копию объекта с вложенностями?

2.0 Middle🔥 221 комментариев
#JavaScript Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Глубокое копирование объектов с вложенностями

Это одна из классических задач в JavaScript. Проблема в том, что при поверхностном копировании (присваивание или spread оператор) копируются только ссылки на вложенные объекты и массивы, а не сами данные.

Проблема поверхностного копирования

const original = {
  name: "John",
  address: {
    city: "Moscow",
    coords: { lat: 55.7558, lng: 37.6173 }
  },
  hobbies: ["reading", "coding"]
};

// Неправильно: поверхностное копирование
const shallow = { ...original };
shallow.address.city = "SPB"; // Изменит и original!
console.log(original.address.city); // "SPB" — БУГ!

Решение 1: JSON.parse + JSON.stringify

Наиболее простой способ для обычных объектов:

const deep = JSON.parse(JSON.stringify(original));
deep.address.city = "SPB";
console.log(original.address.city); // "Moscow" — OK!

Плюсы:

  • Простой синтаксис
  • Встроено в язык
  • Работает с вложенностью любой глубины

Минусы:

  • Не копирует undefined, функции, Symbol, Date (они теряются)
  • Круговые ссылки вызывают ошибку
  • Медленнее других методов

Решение 2: Рекурсивная функция

Для более сложных случаев с функциями и датами:

function deepClone(obj, weakMap = new WeakMap()) {
  // Базовые типы
  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, weakMap));
  }

  // Защита от циклических ссылок
  if (weakMap.has(obj)) {
    return weakMap.get(obj);
  }

  // Обработка Object
  const cloned = {};
  weakMap.set(obj, cloned);
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key], weakMap);
    }
  }

  return cloned;
}

const deep = deepClone(original);
deep.address.city = "SPB";
console.log(original.address.city); // "Moscow"

Преимущества:

  • Сохраняет Date, функции, undefined
  • Обрабатывает циклические ссылки через WeakMap
  • Контролируемо

Решение 3: Структурированное клонирование (HTML5)

const deep = structuredClone(original);

Новый стандартный способ (ES2022), поддерживается в современных браузерах:

  • Копирует Date, Map, Set, ArrayBuffer
  • Автоматически обрабатывает циклы
  • Не копирует функции и DOM элементы

Решение 4: Lodash

import _ from lodash;
const deep = _.cloneDeep(original);

Проверенная батарея, но добавляет зависимость.

Сравнение подходов

СпособПростотаСкоростьФункцииДатаЦиклы
JSON⭐⭐⭐⭐⭐
Рекурсия⭐⭐⭐⭐⭐
structuredClone⭐⭐⭐⭐⭐⭐
Lodash⭐⭐⭐⭐⭐

Практический совет

Для 90% React приложений достаточно JSON решения. Если нужно сохранить функции или обработать циклы — используй structuredClone() или рекурсивную функцию.