Structured Cloning

HTML5 defines an internal "structured" cloning algorithm that can create deep clones of objects. It is still limited to certain built-in types, but in addition to the few types supported by JSON it also supports Dates, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays, and probably more in the future. It also preserves references within the cloned data, allowing it to support cyclical and recursive structures that would cause errors for JSON.

Direct Support in Browsers: Coming Soon?

Browsers do not currently provide a direct interface for the structured cloning algorithm, but a global structuredClone() function is being actively discussed in whatwg/html#793 on GitHub and may be coming soon! As currently proposed, using it for most purposes will be as simple as:

const clone = structuredClone(original);

Until this is shipped, browsers' structured clone implementations are only exposed indirectly.

Asynchronous Workaround: Usable.

The lower-overhead way to create a structured clone with existing APIs is to post the data through one port of a MessageChannels. The other port will emit a message event with a structured clone of the attached .data. Unfortunately, listening for these events is necessarily asynchronous, and the synchronous alternatives are less practical.

Synchronous Workarounds: Awful!

There are no good options for creating structured clones synchronously. Here are a couple of impractical hacks instead.

history.pushState() and history.replaceState() both create a structured clone of their first argument, and assign that value to history.state. You can use this to create a structured clone of any object like this:

Though synchronous, this can be extremely slow. It incurs all of the overhead associated with manipulating the browser history. Calling this method repeatedly can cause Chrome to become temporarily unresponsive.

The Notification constructor creates a structured clone of its associated data. It also attempts to display a browser notification to the user, but this will silently fail unless you have requested notification permission. In case you have the permission for other purposes, we'll immediately close the notification we've created.

When an array contains numbers and strings - functions like .slice(), .concat(), .splice(), the assignment operator "=", and Underscore.js's clone function; will make a deep copy of the array's elements.