JSON.parse(JSON.stringify()) is the most familiar deep-copy trick in JavaScript, but it silently corrupts your data: Dates turn into strings, Maps and Sets become empty objects, and an object with a circular reference throws right away. structuredClone() — a standard API built into modern browsers and Node.js 17+ — is a true deep copy: it keeps Date, Map, Set, and ArrayBuffer intact, and handles circular references as well.
The Problem
Say you need to duplicate a config object before editing it, so you can roll back when the user clicks Cancel. Many developers stringify the object to JSON and parse it back — fast, no library needed — but the price is in the data types JSON does not understand:
const user = { name: "Linh", createdAt: new Date("2026-11-15T09:00:00"), tags: new Set(["dev", "blog"]),};const copy = JSON.parse(JSON.stringify(user));console.log(typeof copy.createdAt); // "string" — Date type lostconsole.log(copy.tags); // {} — Set is gonecopy.createdAt.getFullYear(); // TypeError: getFullYear is not a function
And that is not all: a single circular reference — common in folder trees or state with parent–child relationships — makes JSON.stringify throw immediately:
const node = { value: 1 };node.next = node;JSON.stringify(node); // TypeError: Converting circular structure to JSON
The result: data types lost, and no copy at all.
The Solution
structuredClone() was built for exactly this job. It is a global function, no import needed, and returns a fully independent deep copy:
const user = { name: "Linh", createdAt: new Date("2026-11-15T09:00:00"), tags: new Set(["dev", "blog"]),};user.self = user; // circular reference — still clones fineconst copy = structuredClone(user);console.log(copy.createdAt instanceof Date); // trueconsole.log(copy.tags.has("dev")); // trueconsole.log(copy.self === copy); // true — the cycle is preservedcopy.name = "Changed";console.log(user.name); // "Linh" — the original is untouched
Three things worth noting: data types are preserved — a Date stays a Date, a Set stays a Set. Circular references keep their structure: copy.self points to the copy itself, not to the original. And the copy is fully independent: editing it never affects the source object. The function also accepts a { transfer } option to move ownership of an ArrayBuffer instead of copying it — handy when sending large data to a worker.
Apply It to Your Project
Use structuredClone whenever you need a quick “snapshot” of state before changing it: a form being edited, filters being picked, settings before applying a preset. A familiar pattern: save a copy when the edit form opens, overwrite the original data only when the user clicks Save — click Cancel and the copy is simply discarded. Keep two limits in mind: the function cannot copy functions, DOM nodes, or WeakMaps (it throws DataCloneError), and objects created from a class lose their prototype — the copy keeps only the data, not the class methods.
Related Posts
- JavaScript: fetch() Has No Built-in Timeout — Cancel Hanging Requests with AbortController in 5 Minutes
- JavaScript: Run Multiple Promises at Once with Promise.allSettled — One Failure Won’t Ruin the Batch
- Temporal “về đích”: JavaScript cuối cùng cũng có API xử lý ngày giờ chuẩn — dùng được ngay trên Chrome, Firefox và Node 26
Frequently Asked Questions
Where can I use structuredClone?
Node.js 17+ and all modern browsers (Chrome 98+, Firefox 94+, Safari 15.4+). On older environments, use lodash cloneDeep, or accept JSON when the data only contains simple types.
Can structuredClone copy functions?
No. Functions, DOM nodes, WeakMaps, and WeakSets throw a DataCloneError. The function is only for plain data — objects, arrays, Date, Map, Set, and ArrayBuffer.
What happens to objects created from a class?
The data is preserved, but the prototype is lost: the copy becomes a plain object with no class methods. To keep the methods, write your own clone method in the class, or serialize and restore through the constructor.
Is structuredClone faster than JSON.parse(JSON.stringify())?
For small, simple data, the JSON trick is usually a bit faster. But with data that contains Date, Map, Set, or circular references, structuredClone is both correct and error-free — so correctness should win.
When should I still use JSON.parse(JSON.stringify())?
When the data only contains strings, numbers, booleans, arrays, and plain objects, and you need compatibility with very old environments. It is also useful when you deliberately want to “clean” an object — dropping undefined values and functions before saving.
💬 Have you tried this in your own project? If you hit an error or know a shorter way, leave a comment below — I read them all and will add the best ideas to the post.
References
- MDN Web Docs — structuredClone(): https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
- Node.js Docs — structuredClone(): https://nodejs.org/api/globals.html#structuredclonevalue-options
