Deep Cloning in JavaScript: How to Clone Objects and Arrays

Simple, reliable method for deep cloning objects and arrays in JavaScript to avoid common pitfalls in data manipulation.

#javascript
#nodejs
#object
Deep Cloning in JavaScript: How to Clone Objects and Arrays
Picture by Daniel K Cheung

The Problem

Thanks to native methods for arrays and objects, such as Array.prototype.slice and Object.assign, we are able to create new references for our data copying all the properties/elements in a new instance. But the problem comes when our lists contain nested objects/arrays. Since they are stored in memory with a reference, the implementation of .slice and .assign will just copy that associated address:

js
const arr = [1, 2, { name: 'Marco' }];
const obj = { name: 'Marco', skills: ['JavaScript'] };
const copyArr = arr.slice();
const copyObj = Object.assign({}, obj);

arr === copyArr; // false, OK
obj === copyobj; // false, OK
arr[2] === copyArr[2]; // true! What???
obj.skills === copyObj.skills; // true! What???

So, how can we create a deep copy that always creates new instances of our nested properties?

The Solution

There are tons of solutions available online, and many libraries like Lodash already provide a solution. But I hope you’ll like my solution. First, it might be useful to understand what happens behind the scenes:

js
function clone(input) {
if (input === null || typeof input !== 'object') return input;

const output = input.constructor();

for (const key of Object.keys(input)) {
output[key] = clone(input[key]);
}

return output;
}

const arr = [1, 2, { name: 'Marco' }];
const obj = { name: 'Marco', skills: ['JavaScript'] };
const copyArr = clone(arr);
const copyObj = clone(obj);

arr === copyArr; // false, OK
obj === copyObj; // false, OK
arr[2] === copyArr[2]; // false, OK
obj.skills === copyObj.skills; // false, OK

As you can see, it’s pretty simplistic and easy to read, but it does its job well.

It takes an input of any type and returns a new instance, copying all the properties and invoking recursively the function if a nested object/array is found.

Keep in mind that some types don’t necessarily need to be cloned, such as functions or symbols, so it's safe to copy their reference.

Last updated: