<MyRusakov.ru />

Профессия Web-разработчик

Профессия Web-разработчик

Этот комплект за 8 месяцев превратит Вас в Web-разработчика с нуля. Учиться достаточно 1 час в день.

Начнёте Вы с HTML, CSS и вёрстки сайтов. Потом перейдёте к программированию и JavaScript. Затем изучите PHP, MySQL, SQL, Python. Изучите Web-фреймворки Laravel и Django. Создадите 5 своих сайтов для портфолио.

Комплект содержит:

- 540 видеоуроков

- 110 часов видео

- 1205 заданий для закрепления материала из уроков

- 5 финальных тестов

- 7 сертификатов

- 12 Бонусных курсов

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Глубокое копирование объекта в JavaScript: structuredClone, JSON и лучшие практики

Глубокое копирование объекта в JavaScript: structuredClone, JSON и лучшие практики

Запрос «глубокое копирование в JavaScript» стабильно популярен среди начинающих и продолжающих разработчиков. В статье вы узнаете, чем поверхностная копия отличается от глубокой, когда она действительно нужна и какие способы лучше использовать в 2025 году: structuredClone, JSON.parse(JSON.stringify()), lodash.cloneDeep и собственная реализация.

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

Поверхностная копия копирует только верхний уровень объекта, а вложенные объекты остаются по ссылке. Глубокая копия создаёт полностью независимую структуру на всех уровнях вложенности.

const original = { user: { name: 'Ann' }, tags: ['js'] };
const shallow = { ...original }; // поверхностная копия

shallow.user.name = 'Bob';
console.log(original.user.name); // 'Bob' — вложенный объект не скопирован глубоко

Когда действительно нужно глубокое копирование

  • Иммутабельные операции со сложным состоянием (например, в UI-состоянии).
  • Безопасная передача данных между контекстами (Web Workers, postMessage).
  • Формирование снимков состояния (снапшоты) для отката/истории изменений.
  • Избежание неожиданных сайд-эффектов при работе с общими структурами.

Способ 1. structuredClone — современный стандарт

structuredClone — нативный способ глубокого копирования со «структурным» алгоритмом: поддерживает Date, RegExp, Map, Set, ArrayBuffer и TypedArray, а также циклические ссылки. Доступен в современных браузерах и Node.js 17+.

const a = {
  date: new Date(),
  map: new Map([["k", 1]]),
  set: new Set([1, 2]),
  reg: /\d+/g,
  arr: [1, { x: 2 }],
};
a.self = a; // циклическая ссылка

const b = structuredClone(a);

console.log(b !== a); // true
console.log(b.self === b); // true — цикл сохранён корректно
console.log(b.date instanceof Date); // true
console.log(b.map.get("k")); // 1
console.log(b.set.has(2)); // true

Плюсы: быстро, надёжно, поддерживает сложные типы и циклы. Минусы: не переносит функции и DOM-элементы (будут ошибками), BigInt — поддерживается, но в старых окружениях — нет.

Простой безопасный вызов с проверкой поддержки:

function deepCopy(value) {
  if (typeof structuredClone === 'function') return structuredClone(value);
  // Фолбэк — см. ниже про lodash или JSON-метод с оговорками
  throw new Error('structuredClone недоступен. Используйте lodash.cloneDeep или другой способ.');
}

Способ 2. JSON.parse(JSON.stringify()) — быстро, но с потерями

Классический «хак», который часто встречается в статьях. Он прост, но имеет серьёзные ограничения:

  • Теряются функции, undefined, Symbol — они игнорируются.
  • Date превращается в строку, RegExp, Map, Set теряются.
  • BigInt вызовет ошибку при JSON.stringify.
  • Циклические ссылки приводят к ошибке.
const src = { d: new Date(), u: undefined, big: 10n };
try {
  const copy = JSON.parse(JSON.stringify(src));
  console.log(copy.d, typeof copy.d); // "2025-10-19T...", string — это уже не Date
  console.log(copy.u); // undefined пропал
} catch (e) {
  console.error('JSON-способ не сработал:', e.message);
}

Используйте этот метод только для простых сериализуемых структур без функций, дат, BigInt и циклов.

Способ 3. lodash.cloneDeep

Популярная и зрелая библиотека, которая корректно обрабатывает большинство сценариев, где JSON-метод ломается.

// ESM
import cloneDeep from 'lodash.clonedeep';

const state = { a: { b: 1 }, list: [1, 2, { x: 3 }] };
const copy = cloneDeep(state);

console.log(copy !== state); // true
console.log(copy.a !== state.a); // true — глубокая копия

Плюсы: надёжно, знакомо, кросс-платформенно. Минусы: дополнительная зависимость и размер бандла (см. политику производительности).

Способ 4. Своя функция deepClone (практичная версия)

Ниже — компактная реализация с учётом массивов, обычных объектов, Date, RegExp, Map, Set, TypedArray и циклических ссылок (WeakMap). Не копирует методы прототипов и нестандартные объекты DOM.

function deepClone(value, weak = new WeakMap()) {
  if (typeof value !== 'object' || value === null) return value;
  if (weak.has(value)) return weak.get(value);

  if (value instanceof Date) return new Date(value.getTime());
  if (value instanceof RegExp) return new RegExp(value.source, value.flags);

  if (value instanceof Map) {
    const res = new Map();
    weak.set(value, res);
    value.forEach((v, k) => res.set(deepClone(k, weak), deepClone(v, weak)));
    return res;
  }

  if (value instanceof Set) {
    const res = new Set();
    weak.set(value, res);
    value.forEach(v => res.add(deepClone(v, weak)));
    return res;
  }

  // Копируем типизированные массивы
  if (ArrayBuffer.isView(value)) {
    return new value.constructor(value);
  }

  if (Array.isArray(value)) {
    const res = [];
    weak.set(value, res);
    for (let i = 0; i < value.length; i++) {
      res[i] = deepClone(value[i], weak);
    }
    return res;
  }

  // Обычный объект (без сохранения прототипа)
  const res = {};
  weak.set(value, res);
  for (const key of Object.keys(value)) {
    res[key] = deepClone(value[key], weak);
  }
  return res;
}

// Пример
const obj = { a: 1, d: new Date(), r: /x/g, m: new Map([[{ k: 1 }, 2]]), s: new Set([1, { z: 3 }]) };
obj.self = obj;
const copy = deepClone(obj);
console.log(copy.self === copy); // true

Эта версия подходит для большинства бытовых задач. Если нужно сохранять прототипы, дескрипторы свойств и т.п., алгоритм усложнится — в таких случаях рассмотрите structuredClone или специализированные библиотеки.

Производительность и практические советы

  • Глубокое копирование дороже по CPU и памяти. Избегайте его в горячих путях и больших циклах.
  • Используйте иммутабельные паттерны: меняйте только затронутые ветви, а не весь объект целиком.
  • Для state-менеджмента рассмотрите Immer: он создаёт неизменяемые копии с структурным шарингом (минимум дубликатов).
  • Для обмена данными с Web Worker используйте structuredClone — он же лежит в основе postMessage в современных движках.
  • Замерьте: иногда достаточно поверхностной копии + точечного копирования нужной ветви.

Чек-лист выбора способа

  • Нужно быстро и нативно, есть современные окружения? — structuredClone.
  • Простые JSON-данные без дат, функций, BigInt и циклов? — JSON.parse(JSON.stringify()).
  • Нужна стабильность в разных окружениях проекта? — lodash.cloneDeep.
  • Особые требования, контроль над алгоритмом? — своя функция (или доработка).

Что дальше изучить

Чтобы уверенно работать с объектами, коллекциями и типами в реальных проектах, рекомендую пройти практический курс с заданиями и разбором типичных ошибок. Посмотрите программу и примеры уроков: Прокачать JavaScript до уверенного уровня на курсе «JavaScript с Нуля до Гуру 2.0» — хороший следующий шаг после этой статьи.

Итог: для глубокого копирования в JavaScript в 2025 году самым простым и надёжным решением остаётся structuredClone. В остальных случаях выбирайте подход, исходя из ограничений данных, совместимости и производительности вашего приложения.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.