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

Какой есть нюанс при копировании объекта через JSON.stringify?

2.0 Middle🔥 192 комментариев
#JavaScript Core#Браузер и сетевые технологии

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

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

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

Нюансы копирования объектов через JSON.stringify()

Копирование объектов через JSON.stringify() с последующим JSON.parse() — распространённый приём для создания глубокой копии (deep clone), но у него есть критические ограничения, которые важно учитывать.

Основные проблемы и нюансы

1. Потеря типов данных, не поддерживаемых JSON

JSON поддерживает ограниченный набор типов: строки, числа, булевы значения, null, объекты и массивы. Всё остальное сериализуется неожиданным образом или полностью теряется:

const original = {
  date: new Date('2023-01-01'),
  number: NaN,
  infinity: Infinity,
  undefined: undefined,
  function: () => console.log('test'),
  regexp: /test/gi,
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3]),
  bigint: 9007199254740991n,
  symbol: Symbol('id')
};

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

console.log(cloned.date); // "2023-01-01T00:00:00.000Z" (строка, не Date)
console.log(cloned.number); // null
console.log(cloned.infinity); // null
console.log(cloned.undefined); // отсутствует в объекте
console.log(cloned.function); // отсутствует в объекте
console.log(cloned.regexp); // {}
console.log(cloned.map); // {}
console.log(cloned.set); // {}
// bigint и symbol вообще вызовут ошибку при JSON.stringify()

2. Обработка специальных числовых значений

NaN, Infinity, -Infinity преобразуются в null при сериализации, что может привести к потере семантики и ошибкам в вычислениях.

3. Потеря методов и прототипов

Любые методы объекта и связь с прототипом полностью теряются:

class Person {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    return `Hello, ${this.name}!`;
  }
}

const person = new Person('Alice');
const clonedPerson = JSON.parse(JSON.stringify(person));

console.log(person.greet()); // "Hello, Alice!"
console.log(clonedPerson.greet); // undefined
console.log(clonedPerson instanceof Person); // false

4. Циклические ссылки вызывают ошибку

Если объект содержит циклические ссылки, JSON.stringify() завершится с ошибкой:

const obj = { name: 'Test' };
obj.self = obj; // Циклическая ссылка

try {
  JSON.stringify(obj);
} catch (error) {
  console.error(error.message); // "Converting circular structure to JSON"
}

5. Потеря undefined значений

В объектах свойства со значением undefined либо преобразуются в null (в массивах), либо полностью опускаются (в объектах):

const obj = { a: undefined, b: 1 };
const arr = [undefined, 2];

console.log(JSON.stringify(obj)); // '{"b":1}'
console.log(JSON.stringify(arr)); // '[null,2]'

6. Особенности с функциями-сериализаторами

Хотя JSON.stringify() принимает вторым аргументом функцию replacer, которая может частично решить некоторые проблемы, это усложняет код и не решает все вопросы:

const obj = { date: new Date(), value: 42 };
const replacer = (key, value) => {
  if (value instanceof Date) {
    return { __type: 'Date', value: value.toISOString() };
  }
  return value;
};

const str = JSON.stringify(obj, replacer);
// Теперь нужно будет и reviver для JSON.parse, что добавляет сложности

Когда этот подход уместен?

Несмотря на недостатки, метод JSON.parse(JSON.stringify()) полезен в определённых сценариях:

  • Копирование простых data-объектов (без методов, классов и специальных типов)
  • Быстрое глубокое копирование для иммутабельных обновлений в состоянии приложения
  • Подготовка данных для отправки на сервер
  • Создание снимка состояния для отладки

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

Для надёжного глубокого копирования рассмотрите:

  1. Специализированные библиотеки (Lodash _.cloneDeep, Ramda):

    import { cloneDeep } from 'lodash';
    const cloned = cloneDeep(original);
    
  2. Нативные API (для определённых структур):

    // Для Map и Set
    const clonedMap = new Map(originalMap);
    const clonedSet = new Set(originalSet);
    
  3. Собственная рекурсивная функция с обработкой специальных случаев.

  4. HTML Structured Clone Algorithm (в современных браузерах):

    const cloned = structuredClone(original);
    

Вывод

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

Какой есть нюанс при копировании объекта через JSON.stringify? | PrepBro