2HAASStart a project
All posts

Code Snippets

structuredClone: deep copy objects in JavaScript

The spread operator copies only one level, and the JSON trick loses dates and breaks on cycles. structuredClone makes a true deep copy with one built-in call.

The 2HAAS team2 min read

Copying an object in JavaScript looks simple and hides a trap. The spread operator copies only the first level. Nested objects are still shared.

const original = { user: "Rafi", address: { city: "Dhaka" } };

const shallow = { ...original };
shallow.address.city = "Chattogram";

console.log(original.address.city); // "Chattogram": the nested object is shared

Change the copy and the original changes with it. Bugs of this kind are hard to trace, because the line that breaks is far from the line that caused it.

The built-in fix

const deep = structuredClone(original);
deep.address.city = "Sylhet";

console.log(original.address.city); // "Dhaka": the original is untouched

structuredClone() returns a full copy with no shared references, however deep the object goes. It is a global function in all current browsers and in Node.js 17 and later. There is nothing to install.

Better than the JSON trick

For years the common workaround was JSON.parse(JSON.stringify(value)). It works for plain data and fails quietly for everything else.

Value JSON round trip structuredClone
Date Becomes a string Stays a Date
Map and Set Become empty objects Copied correctly
undefined Dropped Kept
NaN and Infinity Become null Kept
BigInt Throws Copied
Circular reference Throws Copied correctly
Typed arrays and ArrayBuffer Mangled Copied
const order = { placedAt: new Date(), tags: new Set(["gift"]) };
order.self = order; // a circular reference

const copy = structuredClone(order);
copy.placedAt instanceof Date; // true
copy.tags.has("gift"); // true
copy.self === copy; // true

What it cannot copy

  • Functions. An object with a function property throws a DataCloneError.
  • DOM nodes. Use node.cloneNode(true) for those.
  • Class instances. The data is copied, but the result is a plain object. The prototype and its methods are gone.
  • Getters and setters. The getter runs and its current value is copied.

If your objects carry methods, write a clone() method on the class instead.

Moving instead of copying

For large binary data, copying is wasteful. The transfer option hands the memory over without duplicating it.

const buffer = new ArrayBuffer(1024 * 1024);
const moved = structuredClone(buffer, { transfer: [buffer] });
// buffer is now empty, and moved owns the memory

When to use it

  • before changing data you received from somewhere else,
  • to keep a snapshot for undo or for comparing later,
  • when preparing a draft of a form that the user may cancel.

One caution: a deep copy visits every value. Cloning a very large object inside a loop or on every key press will cost you. Clone at the boundaries, not everywhere.

The takeaway

Reach for the spread operator when one level is enough, and for structuredClone when the data is nested. The JSON trick can be retired.

Keep reading

  1. Tech Tips2 min read

    Async error handling in JavaScript: try/catch done right

    Unhandled promise rejections crash Node.js services and leave browser apps quietly broken. Catch async errors with try/catch, .catch and a global safety net.

  2. Code Snippets2 min read

    Web Workers: move heavy work off the main thread

    Heavy JavaScript freezes the page because it shares a thread with the interface. A Web Worker runs that work in the background. A working example and the limits to know.

  3. Code Snippets2 min read

    Promise.allSettled: keep the results that succeeded

    Promise.all throws away every result when one request fails. Promise.allSettled waits for all of them and reports each outcome, so one failure cannot empty a page.

Tell us what’s in the way.

A few lines is enough. You get a candid yes, a candid no, or a sharper question.

  • Working software in week four
  • A reply in one business day
  • Handover is the deliverable

Prefer email? [email protected]

The problem, who it is for, and what is in the way right now.

One business day to a real reply. No sales sequence, no call required.