Почему нельзя использовать JSON.stringify и JSON.parse для глубокого копирования объектов с функциями в JavaScript
Что проверяют
Знаете ли вы, что JSON.stringify это сериализация, а не копирование, и держите ли в голове список того, что при этом теряется. Заодно смотрят, назовёте ли современную замену и её собственные ограничения.
Как отвечать
JSON.stringify переводит значение в формат JSON, а в JSON нет функций. Поэтому пара parse(stringify(x)) возвращает не копию объекта, а копию той его части, которую удалось описать текстом.
Что теряется:
- функции,
undefinedи символы в свойствах объекта выбрасываются, а в массиве превращаются вnull; Dateстановится строкой,Map,SetиRegExpпревращаются в пустой объект;NaNиInfinityзаписываются какnull, аBigIntбросаетTypeError;- теряется прототип: экземпляр класса возвращается простым объектом без методов;
- циклическая ссылка это сразу
TypeErrorпро циклическую структуру; - геттер вызывается, и в копию попадает его значение, а не сам геттер.
const obj = { a: 1, fn: () => 1, d: new Date(), u: undefined };
JSON.parse(JSON.stringify(obj));
// остаётся a, дата стала строкой, fn и u исчезлиЗамена: structuredClone для данных, он умеет Date, Map, Set, типизированные массивы и циклические ссылки. Для объектов с функциями нужен либо обход вручную, либо копирование свойств поверх правильного прототипа, либо готовая функция глубокого клонирования из утилитарной библиотеки.
Где спотыкаются
Считают structuredClone полной заменой. Функции он не клонирует, а бросает DataCloneError, узлы DOM тоже. Прототип класса теряется так же, как у JSON: обратно приходит простой объект.
Второе: путают потерю функции с потерей ссылки на прототип. Метод, объявленный в классе, лежит на прототипе и в перечислимые свойства не попадает, поэтому исчезнет при любом копировании собственных полей, не только через JSON.
Третье: копируют так большие деревья состояния. Сериализация и разбор строки на мегабайт дают заметную паузу в главном потоке, хотя обычно достаточно поверхностной копии и точечной замены изменившейся ветки.