JavaScript-Copying composite data types by value
Usually all the composite data types(arrays, objects) in Javascript are copied by reference. Let us understand with the help of an example.
var arr = [1, 2, 3];
var arr1 = arr;
arr1[0] = 0;
Although we are modifying the 0th index of arr1, the change is reflected in arr as well. Here, the address of arr and arr1 will be pointing to the same memory location. This is called shallow copying.
Therefore, the values of arr and arr1 will be [0, 2, 3].
However, in deep copying the original variable and the new variable are disconnected. So, deep copying enables us to modify the one variable without affecting the other variable. Let us see how deep copying is done in JS.
- Spread Operator:-
Spread operator(…) takes an iterable such as array, string and expands it into individual elements. Let us see how spread operator functions with an example.
let myArr = [‘h’, ‘e’, ‘l’, ‘l’, ‘o’];
…myArr => h e l l o
What spread operator does is, it makes copies of individual elements in the objects which are stored in the memory.
Example:
var data1= {name: ‘Jane’, age: 18};
var data2= {…data1};
data2.name = “Doe”;
data2.age = 20;
console.log(data1);
console.log(data2);
The output of the above mentioned piece of code is given below.
Output:
{ name: ‘Jane’, age: 18 }
{ name: ‘Doe’, age: 20 }
However, spread operator renders ineffective when used for nested objects.
For example:
let arr1 = [1, 2, [3, [4, 5]]];
let arr2 = […arr1];
If we change the value of 0th and 1st index, it works as expected. But, to change the 2nd index of arr2, we need to spread that sub-array as well.
arr2 = […arr1[2]]
So, it is ineffective against deep copying nested objects.
Inorder to overcome this, let us look at another way.
2. Stringify():
All you need to do is to stringify your object and parse it after.
Stringify() method converts javascript object or value to JSON string while parse() method takes a JSON string and transforms it into a Javascript object.
Let us consider the same example as before.
var data1= {name: ‘Jane’, age: 18};
var data2 = JSON.parse(JSON.stringify(data1))
data2.name = “Doe”;
data2.age = 20;
console.log(data1);
console.log(data2);
The output of the above mentioned piece of code is given below.
Output:
{ name: ‘Jane’, age: 18 }
{ name: ‘Doe’, age: 20 }
So, is Stringify() the best way to clone objects in JS?
Maybe, maybe not!!
Stringify() method has its own problems. stringify() works only with primitive data types.
At times, stringify() can lose your data. The main problem with cloning through stringify() is that it does not support methods.
For example:
console.log(JSON.stringify({ key: NaN }));
console.log(JSON.stringify({ key: Infinity }));
The output in both the cases will be {“key”:null}. This is a typical example where you lose data.
Hence, we need to be careful while using stringify() method to clone.
The best way to clone objects would be to use lodash deepClone as deepClone works with functions, symbols.
Refer https://lodash.com/docs/4.17.15#cloneDeep for more info.