Natively deep copy a JavaScript object or array with structuredClone()

OpenJavaScript 0

Last updated: October 24, 2022.

For a long time, copying a JavaScript object has required creative hacks or the need to import an external libary.

The problem is that when you use the intuitive method, both the original and new reference refer to the same underlying object. So editing a copy also edits the original!

Here is an example of the problem, attempting to copy a JavaScript object:

const obj = {
    firstName: "David",
    lastName: "Brent",
    occupation: "Paper merchant",
}

const objCopy = obj;

objCopy.firstName = "Brian"; 
// Changes copy

console.log(objCopy); // Copy updated
// {
//     "firstName": "Brian",
//     "lastName": "Brent",
//     "occupation": "Paper merchant"
// }
console.log(obj); // Original object changed too 😱
// {
//     "firstName": "Brian",
//     "lastName": "Brent",
//     "occupation": "Paper merchant"
// }

The same problem arises for arrays:

const array = ["0", "0", "7"];

const arrayCopy = array;

arrayCopy.push('Bond');
// Changes copy

console.log(arrayCopy); // Copy updated
// [
//     "0",
//     "0",
//     "7",
//     "Bond"
// ]
console.log(array); // The original too! 😠
// [
//     "0",
//     "0",
//     "7",
//     "Bond"
// ]

Native deep copy solution: structuredClone()

Thankfully, there is now a really simple native solution to this problem: the structuredClone() method, which deep copies objects.

Simply pass in a data object into structuredClone() and it will return a copy.

const obj = {
    firstName: "David",
    lastName: "Brent",
    occupation: "Paper merchant",
}

const objCopy = structuredClone(obj);

objCopy.firstName = "Brian"; 
// Changes copy

console.log(objCopy); // Deep copy updated
// {
//     "firstName": "Brian",
//     "lastName": "Brent",
//     "occupation": "Paper merchant"
// }
console.log(obj); // Original remains unchanged ✔️
// {
//     "firstName": "David",
//     "lastName": "Brent",
//     "occupation": "Paper merchant"
// }

It also works for deep copying arrays:

const array = ["0", "0", "7"];

const arrayCopy = structuredClone(array);

arrayCopy.push('Bond');
// Changes copy

console.log(arrayCopy); // Deep copy updated
// [
//     "0",
//     "0",
//     "7",
//     "Bond"
// ]
console.log(array); // The original remains unchanged ✔️
// [
//     "0",
//     "0",
//     "7",
// ]

What about an object with methods?

Unfortunately, structuredClone() does not copy objects that contains functions. If you attempt it, an error will be thrown.

Therefore, for objects with methods, another solution is needed. A popular solution is to use the Lodash deepClone() method.

Browser support

At the time of writing, structuredClone() is supported by all major browsers and in Node.js.

It is not, however, yet supported in Web Workers.