Почему structuredClone() почти всегда лучше, чем JSON.parse(JSON.stringify())

structuredClone() лучше чем JSON.parse
structuredClone() лучше чем JSON.parse

Если вам нужно корректно клонировать данные в современном JavaScript, structuredClone() — это стандартный и безопасный путь, а связка JSON.parse(JSON.stringify()) — лишь обходной приём с жёсткими ограничениями. structuredClone() сохраняет больше типов, умеет работать с циклическими ссылками и поддерживается как веб-платформой, так и Node.js, поэтому он лучше подходит для реального продакшена.

Совет «клонируй объект через JSON.parse(JSON.stringify(obj))» долго жил в статьях, ответах на форумах и кодовой базе старых проектов. Проблема в том, что это не механизм глубокого копирования как таковой, а побочный эффект JSON-сериализации. Он работает только для узкого подмножества значений, которые можно без потерь представить в JSON.

structuredClone() устроен иначе. Это встроенный API, основанный на стандартном алгоритме structured clone, который используется платформой для передачи и копирования данных между разными контекстами исполнения. Именно поэтому он клонирует данные существенно точнее и предсказуемее, чем JSON-хаки. Это зафиксировано в документации MDN и Node.js, а сам алгоритм определён в HTML Standard structured clone algorithm.

Что читатель получает сразу: меньше потерь данных, меньше скрытых багов, больше совместимости с реальными структурами

Главная практическая выгода проста: structuredClone() копирует данные ближе к их реальной структуре в памяти, а не пытается сначала превратить их в JSON-строку.

Это означает три ключевых преимущества:

  • сохраняются типы, которые JSON ломает или отбрасывает;
  • корректно обрабатываются циклические ссылки;
  • API явно предназначен именно для глубокого клонирования, а не используется «не по назначению».

Для прикладной разработки это особенно важно, когда в объектах встречаются:

  • Date
  • Map
  • Set
  • ArrayBuffer и typed arrays
  • Blob, File и другие веб-типы
  • вложенные графы объектов с повторными ссылками
  • циклические структуры

JSON-подход в этих случаях либо искажает данные, либо выбрасывает исключение, либо тихо удаляет часть информации.

Почему JSON.parse(JSON.stringify()) изначально был плохой заменой глубокому клонированию

Это не clone API, а сериализация в другой формат

JSON.stringify() предназначен для преобразования значения в JSON-строку. Затем JSON.parse() строит по этой строке новое значение. То есть данные проходят через формат JSON, а JSON поддерживает далеко не все сущности JavaScript.

По документации MDN, при сериализации JSON:

MDN: JSON.stringify()

  • undefined, Function и Symbol в объектах отбрасываются;
  • в массивах такие значения превращаются в null;
  • Date превращается в строку;
  • Map и Set не сериализуются в полезном виде без дополнительной логики;
  • при циклической ссылке JSON.stringify() выбрасывает TypeError

Именно поэтому такая конструкция может выглядеть рабочей на простых plain object, но начинает подводить сразу, как только модель данных становится чуть сложнее.

Потери происходят не только на экзотических типах

Опасность JSON-подхода в том, что он ломает не только редкие случаи. Даже вполне обычный Date после «клонирования» уже не Date, а строка. Это меняет поведение программы: исчезают методы экземпляра, меняются проверки типов, ломается логика сравнения и форматирования.

Аналогично с Map и Set: формально код может не упасть, но семантика данных уже потеряна. Это один из самых неприятных видов ошибок — не явное исключение, а тихое искажение результата.

Циклические ссылки делают JSON-подход непригодным

Если объект содержит ссылку сам на себя или цикл через вложенные объекты, JSON.stringify() не сможет его обработать и завершится ошибкой. Для сложных состояний приложения, графов связей и кэшей это обычная ситуация, а не экзотика.

structuredClone() как раз рассчитан на такие структуры и поддерживает циклические ссылки в рамках стандартного алгоритма.

Что делает structuredClone() и почему он надёжнее

structuredClone() создаёт глубокую копию значения с помощью алгоритма structured clone, используемого веб-платформой. MDN прямо указывает, что метод создаёт deep clone и поддерживает transferables, позволяя переносить передаваемые объекты вместо копирования MDN: Window.structuredClone().

Ключевые свойства API:

  • создаёт глубокую копию;
  • поддерживает циклические ссылки;
  • умеет работать со многими встроенными типами, недоступными JSON;
  • поддерживает transfer list для некоторых бинарных объектов;
  • доступен в браузерах и Node.js как стандартный встроенный механизм.

В Node.js structuredClone() также документирован как глобальная функция, совместимая с методом structuredClone веб-платформы. Это важно для fullstack- и server-side-разработки: один и тот же подход применим и в браузере, и на сервере.

Сравнение поведения на реальных типах данных

Ниже — практическое сравнение того, что происходит с разными типами.

Тип данныхJSON.parse(JSON.stringify())structuredClone()
Plain object / arrayОбычно работаетРаботает
DateПревращается в строкуСохраняется как Date
MapТеряет структуру без спецобработкиСохраняется как Map
SetТеряет структуру без спецобработкиСохраняется как Set
Циклические ссылкиОшибкаРаботает
ArrayBufferНеприменимо как нормальный cloneПоддерживается
undefined в объектеСвойство исчезаетСохраняется
FunctionНе сериализуетсяНе клонируется стандартным алгоритмом
SymbolТеряетсяНе клонируется как обычное значение данных

Здесь важен нюанс: structuredClone() не «клонирует вообще всё подряд». Например, функции не поддерживаются алгоритмом structured clone. Но разница в том, что ограничения API прозрачны и стандартизованы, а не замаскированы под «вроде глубокую копию».

Где structuredClone() особенно выигрывает

1. При работе со сложным состоянием приложения

Состояние UI, кеши, снапшоты и промежуточные модели часто содержат не только простые литералы, но и даты, множества, карты, бинарные данные и внутренние ссылки. В таких структурах JSON-клонирование даёт либо поломку, либо деградацию типов.

2. При передаче данных между потоками и контекстами

Алгоритм structured clone лежит в основе обмена данными во многих API веб-платформы. Это значит, что structuredClone() ближе к реальной модели работы среды, чем ручная сериализация в JSON.

3. Когда важна предсказуемость

JSON.parse(JSON.stringify()) хорош только пока входные данные случайно соответствуют ограничениям JSON. structuredClone() лучше тем, что его поведение согласовано со стандартом и описано как механизм копирования, а не как побочный эффект сериализатора.

Важное ограничение: structuredClone() — не универсальный «клон всего на свете»

У structuredClone() есть границы применимости, и это нужно понимать заранее.

Он не предназначен для копирования:

  • функций;
  • DOM-узлов;
  • некоторых объектов с внутренним поведением, не поддержанным structured clone algorithm.

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

Нужно ли полностью забыть про JSON.parse(JSON.stringify())

Почти всегда — да, если речь именно о глубоком клонировании.

У JSON-подхода остаётся очень узкая легитимная ниша: когда вы сознательно хотите получить JSON-представимое значение и заранее знаете, что вход содержит только сериализуемые в JSON данные. Но это уже не «глубокое клонирование объекта JavaScript», а нормализация структуры под формат JSON.

То есть вопрос стоит так:

  • если нужна копия данных как JavaScript-структуры — используйте structuredClone();
  • если нужна именно JSON-сериализация — используйте JSON-методы.

Подмена одной задачи другой и породила многолетнюю привычку к JSON.parse(JSON.stringify()).

Когда миграция на structuredClone() даст самый заметный эффект

Переход особенно оправдан, если в проекте встречаются:

  • странные баги после «клонирования» объекта;
  • исчезающие поля со значением undefined;
  • неожиданные строки вместо Date;
  • проблемы с Map, Set, typed arrays;
  • ошибки на циклических структурах;
  • необходимость единообразного клонирования в браузере и Node.js.

Во всех этих случаях structuredClone() не просто «современнее», а фундаментально корректнее по отношению к данным.

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

JSON.parse(JSON.stringify()) — это старый обходной манёвр, который работает только на простых JSON-совместимых значениях и часто портит данные без явного сигнала. structuredClone() лучше потому, что это официальный механизм глубокого клонирования, рассчитанный на реальные типы JavaScript и веб-платформы, включая циклические ссылки и специализированные встроенные объекты.

Если вам нужен именно deep clone, а не преобразование в JSON, выбирать стоит structuredClone(). Сегодня это не вопрос стиля, а вопрос корректности.

При использовании материалов сайта необходимо указывать ссылку на TGLand.ru. Если вы копируете фрагменты текста в интернете, прямая гиперссылка, доступная для индексации поисковыми системами, должна быть размещена в начале материала.

Вам также может понравиться