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

Приведи пример глубокого копирования

1.6 Junior🔥 131 комментариев
#JavaScript Core

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Глубокое копирование в JavaScript

Глубокое копирование — это создание нового объекта со всеми вложенными структурами данных, скопированными полностью, а не по ссылке. Это критично при работе с состоянием в React и сложными объектами.

Почему это нужно

// Проблема: поверхностное копирование
const original = { user: { name: "John", age: 30 } };
const copy = { ...original }; // Shallow copy

copy.user.name = "Jane";
console.log(original.user.name); // "Jane" — original изменился!

Вложенные объекты остаются ссылками, а не копируются.

Решение 1: JSON метод (простой, но с ограничениями)

const original = {
  name: "John",
  hobbies: ["reading", "coding"],
  address: { city: "New York", zip: "10001" }
};

const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.address.city = "Boston";
console.log(original.address.city); // "New York" — оригинал не изменился

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

  • Просто и понятно
  • Работает для большинства объектов

Недостатки:

  • Теряются методы и функции
  • Теряются Symbol и undefined
  • Не работает с Date, Map, Set, RegExp
const data = {
  date: new Date(),
  copy: JSON.parse(JSON.stringify(data));
};
console.log(copy.date); // Строка, не Date объект!

Решение 2: Рекурсивная функция (универсальное)

function deepCopy(obj) {
  // Базовые типы
  if (obj === null || typeof obj !== "object") return obj;
  
  // Специальные объекты
  if (obj instanceof Date) return new Date(obj.getTime());
  if (obj instanceof Map) return new Map(obj);
  if (obj instanceof Set) return new Set(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  
  // Массивы
  if (Array.isArray(obj)) {
    return obj.map(item => deepCopy(item));
  }
  
  // Обычные объекты
  const copy = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  return copy;
}

const original = {
  name: "John",
  hobbies: ["reading", "coding"],
  createdAt: new Date(),
  tags: new Set(["js", "frontend"])
};

const copy = deepCopy(original);
copy.tags.add("react");
console.log(original.tags); // Set(2) { 'js', 'frontend' }

Решение 3: structuredClone (современный стандарт)

const original = {
  name: "John",
  hobbies: ["reading", "coding"],
  createdAt: new Date()
};

const copy = structuredClone(original);

copy.hobbies.push("gaming");
copy.createdAt.setFullYear(2025);

console.log(original.hobbies); // ["reading", "coding"]
console.log(original.createdAt); // 2026-04-02

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

  • Встроенный метод браузера
  • Работает с Date, Map, Set, Blob и др.
  • Самый надёжный вариант

Недостатки:

  • Может быть медленнее на больших объектах
  • Не копирует функции

Решение 4: Lodash (если нужна сложная логика)

import _ from "lodash";

const original = { user: { name: "John" } };
const copy = _.cloneDeep(original);

В контексте React

function UserProfile() {
  const [state, setState] = useState({
    user: { name: "John", address: { city: "NY" } }
  });

  const handleCityChange = (newCity) => {
    // Правильно: создаём новый объект
    const newState = structuredClone(state);
    newState.user.address.city = newCity;
    setState(newState); // React заметит изменение
  };

  return (
    <button onClick={() => handleCityChange("LA")}>
      Сменить город
    </button>
  );
}

Сравнение методов

МетодПростотаУниверсальностьСкорость
JSONВысокаяНизкаяВысокая
structuredCloneВысокаяВысокаяСредняя
РекурсияСредняяВысокаяНизкая
LodashВысокаяВысокаяСредняя

Рекомендация: Используй structuredClone как основной выбор в современных браузерах. Для старых браузеров или сложных случаев — рекурсивную функцию или Lodash.

Приведи пример глубокого копирования | PrepBro