How To Clone An Array In Javascript
Overview
Every action can be performed in a variety of ways in the JavaScript language. Copying or cloning an array is not any different, we can do it in many ways like by using loops, Array methods like map, filter, reduce, slice, etc. For beginners, copying or cloning an array in JavaScript might be confusing but this article explains the copying of an array from the very basic concepts with an easy to understand approach.
Introduction
The mutable characteristic of an array in JavaScript must be taken into account whenever we want to clone it. The array cannot simply be copied from one variable to another using the equal to (=) operator. This will result in the array's references being copied rather than its values, or its elements, as both the arrays will refer to the same references of values, this is known as Shallow copying of the array. We have to perform Deep copying of our array so that the elements of the array are copied rather than the reference.
Shallow Copying: The reference of an array is copied during shallow copying. In both the original and the duplicate, the elements or the values remain the same but if we change anything in the duplicate array it will also be visible in the original array.
Deep Copying: The elements, values, or objects in the array are copied during deep copying. In other words, it copies every value or object from the original array to the duplicate array. Here, if we change anything in the duplicate array, it will not affect the original array in any way.
In the above image, the reference of array A is copied to array B using the = operator and it makes a shallow copy. When we use the (...) spread operator (discussed later in the article) it copies the array values to the array B, not the reference of the array A.
JavaScript provides us with some JavaScript copy array methods specific for copying or cloning arrays. For example, the Array.slice() method, Array.from() is another similar method for copying an array. In ES6, a spread operator (...) is introduced, which also simplifies the process of copying the array in JavaScript.
Why Can’t I Use = to Copy an Array?
Array variable names in JavaScript store the reference values, and attempting to clone an array using the = operator will only copy a reference to the original array, not all the array's values. Thus, any modifications in the duplicate array will be visible in the original array as well and vice versa. You must duplicate the array's value to a new array to make a true copy of an array. In this way, the original array in the memory is not referenced (not affected in any way) by the duplicate array modifications.
Output:
Explanation: In the above program, nums and nums2 are pointing to the same array elements in the memory as we are using = to assign the nums array to the nums2 array, but when we use the spread operator (...), it copies the nums array values to the cloneArray and stores a different array reference.
Problem with Reference Values
The immutability of arrays is extremely important when we are dealing with frameworks like Redux. An object is said to be immutable if its state cannot be changed once it is created, but due to the array's mutability in JavaScript, it creates a possibility of data modification from different reference values from different parts of the project, and that may result in a lot of bugs in the project. So, to avoid this possibility, we prefer deep copying of an array in JavaScript. Let's look at an example:
Output:
Explanation: In the above program, we are trying to copy the nums array to the nums2 array using the = operation, but the = operation copies the reference value of the nums array to the nums2 array. So, when we modify the nums2 array, the changes are also visible in the nums array. That's why we need to clone an array and we will see many different methods in the below article to clone an array.
Mutable vs Immutable Data Types
An object that can have its state changed after creation is Mutable, while an object that can't have its state changed after creation is known as Immutable.
Mutable Data Types in JavaScript:
- objects
- arrays
- functions
Immutable Data Types in JavaScript:
All primitives are immutable.
- number
- string
- symbol
- boolean
- undefined
- null
Spread Operator (...)
This has become the most popular technique since ECMAScript6 was released. You'll find it quite helpful when utilizing it with libraries like React and Redux because it has a simple syntax.
The spread operator in JavaScript allows an iterable to be expanded. Examples of iterables that can be expanded include array expressions, strings, and object expressions.
Example JS Program:
Output:
Explanation: In the above program, we have created a copy of the dogs array in the dogsCopy array using the spread operator (...). The dogs iterable gets expanded into an individual element and is copied to the dogsCopy array. This way, we avoid the reference problem.
NOTE: Spread operator copies an array only one level deep. So, you'll need to use other options if you're trying to clone a multi-dimensional array.
Output:
Explanation: We have cloned the multi-dimensional originalArr using the spread operator (...), but since the array is multi-dimensional, the references for the arrays inside the originalArr get copied in the cloneArr instead of the array itself. So, we must take caution with the spread operator while using multi-dimensional arrays in a JavaScript program.
for() Loop
for() loop can be used to iterate over each element in the original array and copy it to the new array to create a duplicate array. This approach is not that popular because there are other fast alternatives available to clone an array in JavaScript.
Example JS Program:
Output:
Explanation: We are iterating over each element of the nums array using a for() loop and a forEach loop and assigning each element in the numsClone array at the corresponding index.
Note: Multi-dimensional arrays cannot be copied with this. Since we're using the = operator, objects and arrays will be assigned by reference rather than by value.
while() Loop
Similar to the for() loop approach, we can use a while() loop to iterate over and copy each element of an array to create a JavaScript clone array.
Example JS Program:
Output:
Explanation: We are iterating over each element of the nums array using a while() loop and assigning each element in the numsClone array.
Note: Multi-dimensional arrays cannot be copied with this, similar to the for() loop process since we're using the = operator.
Array.map
Array.map() method generates an array with the same size as the original array. For each element of an array, the map() method calls a function to create a new array. For empty items, the function is not run by map(). Also, the original array remains unaffected by the map() method.
Example JS Program:
Output:
Explanation: We are using Array.map method in the above program to create a duplicate array. map() method executes a function for each of the original array elements and the returned values are assigned in the duplicate array.
Note: map() also assigns references rather than values with multi-dimensional arrays.
Array.filter
Similar to map(), Array.filter() function also returns an array, but there is no assurance that the array will be of the same size. filter() also executes a function and checks a condition for every element in the array and if the element satisfies the condition, it is returned.
Example JS Program:
Output:
Explanation: We are using Array.filter method in the above program to create a duplicate array. filter() method checks a condition for each of the nums array elements and when the condition is true, the value is returned and is assigned in the duplicate array numsClone.
Note: filter() also assigns references rather than values with multi-dimensional arrays.
Array.reduce
Array.reduce() runs a reducer function for each element of an array and returns a single value or object, the total outcome of the function.
Example JS Program:
Output:
Explanation: In the above program, we are using reduce function on the nums array. An empty array duplicateArray is used as the beginning value in this case, and each element of the nums array is added one at a time. For the method to be used in the following iteration, that array must be returned. We return the array reference to the numsClone array. It will clone the nums array in the numsClone array.
Note: reduce() also assigns references rather than values with multi-dimensional arrays.
Array.slice
Array.slice() returns a new array with the chosen elements from a given array. We can choose between a specified start and a specified (not all-inclusive) end to slice and copy our array.
Example JS Program:
Output:
Explanation: If we don't pass any arguments to the slice() method, it will return a copy of the current array from the start to the end index. We are assigning the return value in the sliceArray which contains the copy of the originalArray.
Note: slice() also assigns references rather than values with multi-dimensional arrays.
JSON.parse and JSON.stringify
An object is converted to a string using JSON.stringify and a string is converted into an object via JSON.parse. Combining these will convert an object into a string, which will then be converted back into a new data structure.
JSON.parse() and JSON.stringify() are the specific methods used for multi-level deep copying. They are compatible with multi-dimensional arrays and copy the values, instead of references at any level.
Example JS Program:
Output:
Explanation: In the above program, we are using JSON.stringify to convert a multi-dimensional array deepArray into a string and JSON.parse to convert it back to a multi-dimensional array and then assigning it to the deepCopy array. This method returns a copy value and not a reference to any of the array elements. We can see from the output that if we change anything in the deepCopy array, the deepArray remains unaffected.
Note: This method copies arrays that are deeply nested safely!
Array.concat
Array.concat() combines (concatenates) two or more arrays together and a new array comprising the combined arrays is returned. Let's see how we can use concat() to copy an array:
Example JS Program:
Output:
Explanation: If we don't pass any argument in the concat() function it will return a copy of the current array. We are assigning the return value in the numsCopy array.
Note: concat() assigns references rather than values with multi-dimensional arrays.
Array.from
Array.from() is used to convert any iterable object to an array. A copy is produced when an array is passed as an argument in the from() method.
Example JS Program:
Output:
Explanation: We are using Array.from() method which returns an array from any object that is iterable. We are passing nums as an argument in the Array.from() method and the returned value is stored in the numsCopy array.
Note: from() also assigns references rather than values with multi-dimensional arrays. Use this JavaScript Beautifier to beautify your code.
Conclusion
- Copying or cloning an array can be performed in many ways, like by using the spread operator (...), loops, and Array methods like map, filter, reduce, slice, etc.
- The mutable characteristic of an array in JavaScript must be taken into account whenever we want to clone it. The array cannot simply be copied from one variable to another using the equal to (=) operator.
- If we have copied an array using the equal to (=) operator, then any modifications in the duplicate array will be visible in the original array as well and vice versa.
- The reference of an array is copied during shallow copying, while the elements, values, or objects in an array are copied during the deep copying of an array.
- JSON.parse and JSON.stringify are the specific methods used for multi-level deep copying. They are compatible with multi-dimensional arrays and copy the values, instead of references at any level.