JSON.stringify Deep Copy Limitations in JavaScript

Using JSON.parse(JSON.stringify(object)) is a popular and quick hack for deep cloning objects in JavaScript. However, this method relies strictly on the JSON standard rather than native JavaScript data types, which leads to silent data corruption, lost data, or runtime errors. This article outlines the major limitations of using the JSON serialization approach for copying data structures in JavaScript.

1. Functions and Methods Are Omitted

JSON does not support functions. If an object contains methods or properties assigned to a function, JSON.stringify will silently omit them from the resulting object. If a function is stored inside an array, it will be converted into null.

const user = {
  name: "Alice",
  greet: () => console.log("Hello")
};

const copy = JSON.parse(JSON.stringify(user));
console.log(copy); // { name: "Alice" } (greet is missing)

2. undefined and Symbol Values Are Lost

Similar to functions, undefined values and Symbol keys/values are not valid JSON. When stringified: * Object properties with undefined or Symbol values are omitted. * Symbol-keyed properties are completely ignored. * Array elements containing undefined or Symbol are converted to null.

3. Date Objects Are Converted to Strings

JSON does not have a native date type. When a JavaScript Date object passes through JSON.stringify(), its toISOString() method is called, converting the date to a string. When parsed back via JSON.parse(), it remains a string instead of being converted back into a Date instance.

const event = { date: new Date() };
const copy = JSON.parse(JSON.stringify(event));

console.log(typeof copy.date); // "string", not an instance of Date

4. Special Number Types Become null

JavaScript values such as NaN, Infinity, and -Infinity are not represented in the JSON standard. JSON.stringify converts all of these values into null.

const stats = { value: NaN, max: Infinity };
const copy = JSON.parse(JSON.stringify(stats));

console.log(copy); // { value: null, max: null }

5. BigInt Throws a TypeError

JSON.stringify cannot serialize BigInt values by default. Attempting to copy an object that contains a BigInt will throw an unhandled TypeError.

const data = { id: 100n };
JSON.stringify(data); // TypeError: Do not know how to serialize a BigInt

6. Complex Collections (Map, Set, RegExp) Are Cleared

Data structures such as Map, Set, and regular expressions (RegExp) are not recognized as structured objects by JSON: * Map and Set are serialized as empty objects ({}). * RegExp instances are serialized as empty objects ({}). * TypedArrays and Blobs also lose their internal binary representations.

7. Circular References Crash Execution

If an object references itself directly or indirectly, JSON.stringify cannot resolve the recursive structure and will throw an error.

const obj = {};
obj.self = obj;

JSON.stringify(obj); // TypeError: Converting circular structure to JSON

8. Prototype Chains Are Discarded

JSON only serializes enumerable, own properties. It does not preserve the prototype chain. If you clone an instance of a custom class or constructor function, the resulting copy will always be a plain Object, losing all inherited properties and methods.


Better Alternatives

For modern JavaScript environments, consider these alternatives: * structuredClone(): A built-in native API that handles Date, RegExp, Map, Set, BigInt, typed arrays, and circular references. * Libraries like Lodash (cloneDeep): Useful for older environments or when custom cloning behavior is required.