In an earlier article, we looked at different ways to make a copy of an array in JavaScript. However, all these methods only create a shallow copy of the original array.

This means that if the original array contains objects, only their references will be passed to the new array. To create a true copy of an array, you have to create a deep clone, i.e. copy all nested objects and not just their references.

Why Deep Clone?

To understand why we need a deep clone, let us look at the following example:

const animals = [{ cat: '🐱', monkey: '🐒', whale: '🐋' }];

const moreAnimals = [...animals];

// update `cat` key in original array
animals[0].cat = '🐭';

console.log(animals);
// [{ cat: '🐭', monkey: '🐒', whale: '🐋' }]

console.log(moreAnimals);
// [{ cat: '🐭', monkey: '🐒', whale: '🐋' }]

As you can see above, after creating a shallow copy of the array, we changed the cat key value in the original array. But this change is also reflected in the copied array. This is because the copied array still references the objects present in the original array.

JSON Methods

The simplest way to make a deep clone of an array in JavaScript is by using the JSON object methods: JSON.stringify() and JSON.parse():

const animals = [{ cat: '🐱', monkey: '🐒', whale: '🐋' }];

const moreAnimals = JSON.parse(JSON.stringify(animals));

console.log(moreAnimals);

// [{ cat: '🐱', monkey: '🐒', whale: '🐋' }]

In the above example, we first converted the original array to a string by using JSON.stringify() and then parse it back to an array with the help of JSON.parse(). This method works great and it doesn't require any 3rd-party library.

However, there are two downsides to this approach:

  • The array must be compatible with the JSON format. This means that the nested objects must be serializable and deserializable via JSON.
  • It is much slower than other solutions when the array contains a lot of entries.

The JSON methods only work with strings, numbers, and object literals without functions and symbol properties. You'd see a weird behavior when the array contains other values:

// undefined is turned to null
JSON.parse(JSON.stringify([4, 8, undefined])); // [4, 8, null]

// Date object is turned to string
JSON.parse(JSON.stringify([new Date()])); // ["2020-05-23T21:42:13.990Z"]

// function is turned to null
JSON.parse(JSON.stringify([() => {return 'Hi';}])); // [null]

For arrays that contain JSON incompatible values, consider using a 3rd-party library like Lodash to create a deep clone.

Lodash Clone Deep

Lodash provides the _.cloneDeep() method that recursively clones everything in the original array to the new array. It works for all data types, including functions and symbols that are copied by reference.

Here is an example:

const _ = require('lodash');

const animals = [{ cat: '🐱', monkey: '🐒', whale: '🐋' }];

const moreAnimals = _.cloneDeep(animals);

console.log(moreAnimals);

// [{ cat: '🐱', monkey: '🐒', whale: '🐋' }]

It works for JSON incompatible values too:

_.cloneDeep([1, 2, undefined]); // [1, 2, undefined]

const deep = _.cloneDeep([() => {return 'Hi';}]);

console.log(deep[0].call()); // Hi

Take a look at this article to learn more about JavaScript arrays and how to use them to store multiple values in one variable.

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.