Learn how to copy an array in javascript.
There are two different types of copy that can be performed on an array.
1) Shallow Copy.
2) Deep Copy
Shallow copy an array
Arrays in javascript are just objects with some additional properties and methods which make them act like an array. So when we directly assign array to another variable it is shallowly copied.
This means it is just referencing to the array not copying all the elements.
let arr = [1, 2, 3, 4, 5]; //Shallow copy the array let arr2 = arr; console.log(arr2); //[1, 2, 3, 4, 5]; //Update original array arr.push(6); //[1, 2, 3, 4, 5, 6] //Update is reflected in the copied variable console.log(arr2); //[1, 2, 3, 4, 5, 6]
Deep copy an array
We will see different methods through which we can deep copy an array in javascript.
Using ES6 Spread Operator
We can use ...
operator to create a deep clone of a given array.
let arr = [1, 2, 3, 4, 5]; let arr2 = [...arr]; console.log(arr2); //[1, 2, 3, 4, 5] arr[1] = 10; [1, 10, 3, 4, 5]; console.log(arr2); //[1, 2, 3, 4, 5]
You can also use the push()
method to create a deep clone.
let arr = [1, 2, 3, 4, 5]; let arr2 = []; //Deep clone arr2.push(...arr); console.log(arr2); //[1, 2, 3, 4, 5]
This method only works for literal values like Strings, Booleans, Numbers. It does not work for nested arrays, objects, and prototypes.
let arr = [{a: 1}, {b: 2}, {c: 3}]; let arr2 = [...arr]; //[{a: 1}, {b: 2}, {c: 3}]; arr[0].a = 10; console.log(arr); //[{a: 10}, {b: 2}, {c: 3}] console.log(arr2); //[{a: 10}, {b: 2}, {c: 3}];
By concatenating with empty array
We can concatenate the original array with an empty array and return it to make a deep clone.
let arr = [1, 2, 3, 4, 5]; let arr2 = [].concat(arr); console.log(arr2); //[1, 2, 3, 4, 5]
Just like the spread operator, it will only work for literal values only.
let arr = [{a: 1}, {b: 2}, {c: 3}]; let arr2 = [].concat(arr); //[{a: 1}, {b: 2}, {c: 3}]; arr[0].a = 10; console.log(arr); //[{a: 10}, {b: 2}, {c: 3}] console.log(arr2); //[{a: 10}, {b: 2}, {c: 3}];
Just like the above options, we can also use Array.from(), Array.splice() and Array.slice() methods to achieve the same but all of these only deep copy literal values.
Using JSON.parse() and JSON.stringify()
JSON.parse()
converts a string to JSON and JSON.stringify()
converts a JSON to a string.
We can combine them together to create a deep copy of nested arrays and arrays of objects.
let arr = [{a: 1}, {b: 2}, [1, 2]]; let arr2 = JSON.parse(JSON.stringify(arr)); console.log(arr2); //[{a: 1}, {b: 2}, [1, 2]]; arr[0].a = 10; console.log(arr); //[{a: 10}, {b: 2}, [1, 2]]; console.log(arr2); //[{a: 1}, {b: 2}, [1, 2]];
This method works great but you should be really careful about the data that can be stored in JSON.
let arr = [1, undefined, 2]; let arr2 = JSON.parse(JSON.stringify(arr)); // undefineds are converted to nulls console.log(arr2); //[1, null, 2] let arr = [document.body, document.querySelector('p')]; let arr2 = JSON.parse(JSON.stringify(arr)); // DOM nodes are converted to empty objects console.log(arr2); //[{}, {}] let arr = [new Date()]; let arr2 = JSON.parse(JSON.stringify(arr)); // JS dates are converted to strings console.log(arr2); //["2019-05-04T10:26:01.390Z"]
Also, this cannot be used to make a complete deep copy, it will still not work for prototypes.
Using $.extend() of Jquery
$.extend(deep, copyTo, copyFrom)
can be used to make a complete deep copy of any array or object in javascript.
let arr = [{a: 1}, {b: 2}, [1, 2]]; //Deep copy let arr2 = $.extend(true, [], arr); arr[2][0] = 5; console.log(arr2); //[{a: 1}, {b: 2}, [1, 2]]; console.log(arr); //[{a: 1}, {b: 2}, [5, 2]];
You can also use other libraries like lodash, underscore to achieve the same.
Vanilla Javascript
You can also create a custom function to create a deep clone of objects or arrays in vanilla javascript.
let deepCopy = (aObject) => { //If not a object then return if (!aObject) { return aObject; } let v; //Check the type of the input let bObject = Array.isArray(aObject) ? [] : {}; //Copy each element for (const k in aObject) { v = aObject[k]; //If type of element is object //Then recursively call the same function and create a copy bObject[k] = (typeof v === "object") ? deepCopy(v) : v; } return bObject; }
let arr = [{a: 1}, {b: 2}, [1, 2]]; //Create a deep copy let arr2 = deepCopy(arr); //Update the original array arr[2][0] = 10; console.log(arr2); //[{a: 1}, {b: 2}, [1, 2]]