The Problem with Shallow Copies
Every JavaScript developer eventually runs into the reference trap. You create a new object from an old one using the spread operator or Object.assign(), change a nested property, and suddenly your original data is mutated. This happens because these methods only perform a shallow copy. They copy the top-level properties, but nested objects still point to the same memory address.
const original = { user: { id: 1 }, status: "active" };
const copy = { ...original };
copy.user.id = 2;
console.log(original.user.id); // Output: 2 (Original changed!)The Flaws of the JSON Hack
For years, the standard workaround was JSON.parse(JSON.stringify(obj)). While this effectively creates a deep copy, it has massive downsides. It strips out functions, ignores Symbols, and destroys complex types. If your object contains a Date, it becomes a string. If it contains a Map or Set, they vanish into empty objects.
const data = {
date: new Date(),
map: new Map([["id", 1]])
};
const badCopy = JSON.parse(JSON.stringify(data));
console.log(typeof badCopy.date); // "string" (Date object lost)
console.log(badCopy.map); // {} (Map lost)The Modern Solution: structuredClone()
Introduced natively in modern browsers and Node.js 17+, structuredClone() is the API we have been waiting for. It handles deep cloning with a built-in algorithm that understands complex JavaScript types. It correctly clones Dates, Sets, Maps, and even handles circular references without crashing.
const complexData = {
timestamp: new Date(),
users: new Set(["Alice", "Bob"]),
meta: { tags: ["admin", "dev"] }
};
const deepCopy = structuredClone(complexData);
deepCopy.meta.tags.push("editor");
console.log(complexData.meta.tags); // ["admin", "dev"] (Original is safe)
console.log(deepCopy.timestamp instanceof Date); // trueWhat structuredClone() Cannot Do
While structuredClone() is significantly better than previous hacks, it is not magic. There are two major things it cannot clone: functions and DOM nodes. If you attempt to clone an object containing a function, the engine will throw a DataCloneError. This is intentional, as cloning closures and execution contexts is computationally expensive and logically ambiguous.
When to Use It
Use structuredClone() whenever you need to manipulate data without affecting the original source, especially when dealing with API responses or complex state management. It is faster than the JSON hack and more reliable than manual recursion. If your project supports modern environments, there is no longer a reason to reach for Lodash cloneDeep or buggy JSON workarounds.




