How to clone a JavaScript object ?

To copy/clone an object in JavaScript, you have the following options:

  1. spread (...)
  2. Object.assign()
  3. JSON.stringify() and JSON.parse()

JavaScript spread (...)

The JavaScript spread operator (...) facilitates the copying of array elements or object properties into another array or object. While useful for shallow copying and merging, it does not handle deep copying or complex nested structures.

const colors = {'R': 'Red', 'G': 'Green','B': 'Blue'}; let copyColors = { ...colors }; copyColors.R = "Violet"
console.log(copyColors.R); //Violet ... changed console.log(copyColors); //{ R: 'Violet', G: 'Green', B: 'Blue' }
console.log(colors.R); //Red .... not changed console.log(colors); //{ R: 'Red', G: 'Green', B: 'Blue' }

When you check the above code, spread (...) operator perform a shallow copy. This means that the "R" value in the copyColors is changed but the original object "colors", you will notice it is not affected.

JavaScript Object.assign()

The JavaScript Object.assign() method serves as a fundamental utility for the duplication or amalgamation of objects. This method holds the capacity to seamlessly copy properties from one or more source objects into a designated target object, facilitating the creation of comprehensive and harmonized object structures.

const colors = {'R': 'Red', 'G': 'Green','B': 'Blue'}; let copyColors = Object.assign({}, colors); copyColors.R = "Violet"
console.log(copyColors.R); //Violet ... changed console.log(copyColors); //{ R: 'Violet', G: 'Green', B: 'Blue' }
console.log(colors.R); //Red .... not changed console.log(colors); //{ R: 'Red', G: 'Green', B: 'Blue' }

When you check the above code, Object.assign() performs a shallow copy. This mean that it only copies properties, not prototype methods. Here, you can see, the "R" value in the copyColors is changed but the original object "colors", you will notice it is not affected.

JSON.parse()

To achieve the replication of a JavaScript object, a strategic approach involves the utilization of both JSON.parse() and JSON.stringify() methods in tandem. JSON.parse() facilitates the conversion of a JSON-formatted string into a corresponding JavaScript object, while JSON.stringify() performs the reverse action by transforming a JavaScript object into a JSON-formatted string. This symphony of operations facilitates the creation of a distinct object with properties mirroring those of the original, effectively accomplishing object duplication.

const colors = {'R': 'Red', 'G': 'Green','B': 'Blue'}; let copyColors = JSON.parse(JSON.stringify(colors)); copyColors.R = "Violet"
console.log(copyColors.R); //Violet ... changed console.log(copyColors); //{ R: 'Violet', G: 'Green', B: 'Blue' }
console.log(colors.R); //Red ... not changed console.log(colors); //{ R: 'Red', G: 'Green', B: 'Blue' }

Above code shows that a deep copy allows you to create a completely independent copy of the original object.

Keep in mind that the above methods perform shallow clones, meaning that nested objects and arrays within the cloned object are still references to the same objects in memory. If you need a deep clone, especially for nested structures, you might need to use dedicated libraries like lodash.cloneDeep().

Here's how you would do it with lodash.cloneDeep():

const _ = require('lodash'); const originalObj = { a: 1, b: { c: 2 } }; const clonedObj = _.cloneDeep(originalObj);

Always consider the depth of cloning required and the complexity of the object structure before selecting the appropriate method for cloning.

Shallow Copy and Deep Copy


copy Javascript object

What is Shallow Copy?

Shallow copying entails the creation of a fresh object that carefully replicates the values present within the original object. This includes copying reference pointers alongside the values, thus mirroring the original object's structure. Consequently, the references within the copied object still direct back to the corresponding objects in the original context. As a result, any modifications made to members stored as references transpire within both the source object and its copied counterpart, as no independent replication of the referenced objects was executed.

What is Deep Copy?

In contrast, deep copying involves the comprehensive duplication of all attributes contained within the source object. This careful process allocates distinct memory addresses for the new object, thereby ensuring isolation from the original. Consequently, alterations applied to the referenced objects within the copied structure remain confined to that specific copy, safeguarding the integrity of other instances of the object from any unintended influence. This method ensures a higher degree of independence between the original and its duplicates, facilitating more robust data isolation and management.

Here is an example of nested object/array.

const colors = { R: 'Red', G: 'Green', B: 'Blue', greenColors: { 'L':'limegreen', 'F':'forestgreen', }, };

Shallow Copy

When using the JavaScript spread operator (...) for object duplication, it results in a shallow copy. This implies that only the immediate properties or elements of the object or array are replicated, while nested or multi-dimensional structures are not fully duplicated. Consequently, in scenarios where the object or array contains further nested objects or arrays, the spread operator fails to capture their content accurately, potentially leading to unintended consequences or incomplete replication.

Let's copy/clone your object using spread(...).

const shallowCopyColors = { ...colors }; shallowCopyColors.R = 'Violet'; shallowCopyColors.greenColors.L = 'PaleGreen';

So here changed the cloned object by changing the 'R' value and nested 'L' value. Let's see the output.

console.log(shallowCopyColors);
//Output: { R: 'Violet', G: 'Green', B: 'Blue', greenColors: { L: 'PaleGreen', F: 'forestgreen' } }
console.log(colors);
//Output: { R: 'Red', G: 'Green', B: 'Blue', greenColors: { L: 'PaleGreen', F: 'forestgreen' } }

From the above code, you can understand that a shallow copy means the first level is copied, deeper levels are referenced.

Deep Copy

Let's take the same example but applying a deep copy using "JSON"

const deepCopyColors = JSON.parse(JSON.stringify(colors )); deepCopyColors.R = 'Violet'; deepCopyColors.greenColors.L = 'PaleGreen'; console.log(deepCopyColors);
//Output: { R: 'Violet', G: 'Green', B: 'Blue', greenColors: { L: 'PaleGreen', F: 'forestgreen' } }
console.log(colors);
//Output: { R: 'Red', G: 'Green', B: 'Blue', greenColors: { L: 'limegreen', F: 'forestgreen' } }

JSON.parse() coupled with JSON.stringify() does provide a mechanism for deep copying an object. As demonstrated by the aforementioned code, deep copying guarantees the creation of an entirely autonomous replica of the source object. However, a vital distinction emerges wherein this method is less optimal due to its inability to encompass function or symbol properties. While deep copying accommodates all data types by duplicating their content, functions and symbols are not replicated, but rather retained as references. Therefore, for a comprehensive and inclusive deep clone that covers all types, it is recommended to utilize a dedicated deep cloning approach that encompasses function and symbol properties without relying on mere references.

Conclusion

Cloning a JavaScript object involves creating a duplicate version that doesn't share references with the original. While the spread operator (...) and Object.assign() are efficient for shallow cloning, for deep cloning that handles nested structures and all data types, using JSON.parse() alongside JSON.stringify() is common, although it won't work with functions or symbols. For a comprehensive deep clone that accommodates all types, dedicated libraries like lodash.cloneDeep() are advisable.