[javascript] Copy array by value

When copying an array in JavaScript to another array:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

I realized that arr2 refers to the same array as arr1, rather than a new, independent array. How can I copy the array to get two independent arrays?

This question is related to javascript arrays

The answer is


When we want to copy an array using the assignment operator ( = ) it doesn't create a copy it merely copies the pointer/reference to the array. For example:

_x000D_
_x000D_
const oldArr = [1,2,3];_x000D_
_x000D_
const newArr = oldArr;  // now oldArr points to the same place in memory _x000D_
_x000D_
console.log(oldArr === newArr);  // Points to the same place in memory thus is true_x000D_
_x000D_
const copy = [1,2,3];_x000D_
_x000D_
console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false
_x000D_
_x000D_
_x000D_

Often when we transform data we want to keep our initial datastructure (e.g. Array) intact. We do this by making a exact copy of our array so this one can be transformed while the initial one stays intact.

Ways of copying an array:

_x000D_
_x000D_
const oldArr = [1,2,3];_x000D_
_x000D_
// Uses the spread operator to spread out old values into the new array literal_x000D_
const newArr1 = [...oldArr];_x000D_
_x000D_
// Slice with no arguments returns the newly copied Array_x000D_
const newArr2 = oldArr.slice();_x000D_
_x000D_
// Map applies the callback to every element in the array and returns a new array_x000D_
const newArr3 = oldArr.map((el) => el);_x000D_
_x000D_
// Concat is used to merge arrays and returns a new array. Concat with no args copies an array_x000D_
const newArr4 = oldArr.concat();_x000D_
_x000D_
// Object.assign can be used to transfer all the properties into a new array literal_x000D_
const newArr5 = Object.assign([], oldArr);_x000D_
_x000D_
// Creating via the Array constructor using the new keyword_x000D_
const newArr6 = new Array(...oldArr);_x000D_
_x000D_
// For loop_x000D_
function clone(base) {_x000D_
 const newArray = [];_x000D_
    for(let i= 0; i < base.length; i++) {_x000D_
     newArray[i] = base[i];_x000D_
 }_x000D_
 return newArray;_x000D_
}_x000D_
_x000D_
const newArr7 = clone(oldArr);_x000D_
_x000D_
console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);
_x000D_
_x000D_
_x000D_

Be careful when arrays or objects are nested!:

When arrays are nested the values are copied by reference. Here is an example of how this could lead to issues:

_x000D_
_x000D_
let arr1 = [1,2,[1,2,3]]_x000D_
_x000D_
let arr2 = [...arr1];_x000D_
_x000D_
arr2[2][0] = 5;  // we change arr2_x000D_
_x000D_
console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference
_x000D_
_x000D_
_x000D_

So don't use these methods when there are objects or arrays inside your array you want to copy. i.e. Use these methods on arrays of primitives only.

If you do want to deepclone a javascript array use JSON.parse in conjunction with JSON.stringify, like this:

_x000D_
_x000D_
let arr1 = [1,2,[1,2,3]]_x000D_
_x000D_
let arr2 = JSON.parse(JSON.stringify(arr1)) ;_x000D_
_x000D_
arr2[2][0] = 5;_x000D_
_x000D_
console.log(arr1);  // now I'm not modified because I'm a deep clone
_x000D_
_x000D_
_x000D_

Performance of copying:

So which one do we choose for optimal performance. It turns out that the most verbose method, the for loop has the highest performance. Use the for loop for really CPU intensive copying (large/many arrays).

After that the .slice() method also has decent performance and is also less verbose and easier for the programmer to implement. I suggest to use .slice() for your everyday copying of arrays which aren't very CPU intensive. Also avoid using the JSON.parse(JSON.stringify(arr)) (lots of overhead) if no deep clone is required and performance is an issue.

Source performance test


Using jQuery deep copy could be made as following:

var arr2 = $.extend(true, [], arr1);

I would personally prefer this way:

JSON.parse(JSON.stringify( originalObject ));

No jQuery needed... Working Example

var arr2 = arr1.slice()

This copys the array from the starting position 0 through the end of the array.

It is important to note that it will work as expected for primitive types (string, number, etc.), and to also explain the expected behavior for reference types...

If you have an array of Reference types, say of type Object. The array will be copied, but both of the arrays will contain references to the same Object's. So in this case it would seem like the array is copied by reference even though the array is actually copied.


If you are in an environment of ECMAScript 6, using the Spread Operator you could do it this way:

_x000D_
_x000D_
var arr1 = ['a','b','c'];_x000D_
var arr2 = [...arr1]; //copy arr1_x000D_
arr2.push('d');_x000D_
_x000D_
console.log(arr1)_x000D_
console.log(arr2)
_x000D_
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>
_x000D_
_x000D_
_x000D_


You can also use ES6 spread operator to copy Array

var arr=[2,3,4,5];
var copyArr=[...arr];

Here is how you can do it for array of arrays of primitives of variable depth:

// If a is array: 
//    then call cpArr(a) for each e;
//    else return a

const cpArr = a => Array.isArray(a) && a.map(e => cpArr(e)) || a;

let src = [[1,2,3], [4, ["five", "six", 7], true], 8, 9, false];
let dst = cpArr(src);

https://jsbin.com/xemazog/edit?js,console


Some of mentioned methods work well when working with simple data types like number or string, but when the array contains other objects these methods fail. When we try to pass any object from one array to another it is passed as a reference, not the object.

Add the following code in your JavaScript file:

Object.prototype.clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (i in this) {
        if (i == 'clone') 
            continue;
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        } 
        else 
            newObj[i] = this[i]
    } return newObj;
};

And simply use

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

It will work.


Make copy of multidimensional array/object:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

Thanks to James Padolsey for this function.

Source: Here


None of these options worked for me as I was dealing with an array of deeply nested objects. For ES6 I found this solution helpful.

const old_array = [{name:"Nick", stats:{age:25,height:2}},{name:"June", stats:{age:20,height:2}}];

const new_array = old_array.map(e => {
  if (e.name === 'June') {
     e = { ...e };
     e.stats = {...e.stats, age: 22};
   }
  return e;
});

Only the new_array will be affected by this.


This is how I've done it after trying many approaches:

var newArray = JSON.parse(JSON.stringify(orgArray));

This will create a new deep copy not related to the first one (not a shallow copy).

Also this obviously will not clone events and functions, but the good thing you can do it in one line, and it can be used for any kind of object (arrays, strings, numbers, objects ...)


An alternative to slice is concat, which can be used in 2 ways. The first of these is perhaps more readable as the intended behaviour is very clear:

var array2 = [].concat(array1);

The second method is:

var array2 = array1.concat();

Cohen (in the comments) pointed out that this latter method has better performance.

The way this works is that the concat method creates a new array consisting of the elements in the object on which it is called followed by the elements of any arrays passed to it as arguments. So when no arguments are passed, it simply copies the array.

Lee Penkman, also in the comments, points out that if there's a chance array1 is undefined, you can return an empty array as follows:

var array2 = [].concat(array1 || []);

Or, for the second method:

var array2 = (array1 || []).concat();

Note that you can also do this with slice: var array2 = (array1 || []).slice();.


You could use ES6 with spread Opeartor, its simpler.

arr2 = [...arr1];

There are limitations..check docs Spread syntax @ mozilla


You can do that in following way :
arr2 = arr1.map(x => Object.assign({}, x));


Quick Examples:

  1. If elements in the array are primitive types (string, number, etc.)

_x000D_
_x000D_
var arr1 = ['a','b','c'];_x000D_
// arr1 and arr2 are independent and primitive elements are stored in _x000D_
// different places in the memory_x000D_
var arr2 = arr1.slice(); _x000D_
arr2.push('d');_x000D_
console.log(arr1); // [ 'a', 'b', 'c' ]_x000D_
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]
_x000D_
_x000D_
_x000D_

  1. If elements in the array are object literals, another array ({}, [])

_x000D_
_x000D_
var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];_x000D_
// arr1 and arr2 are independent and reference's/addresses are stored in different_x000D_
// places in the memory. But those reference's/addresses points to some common place_x000D_
// in the memory._x000D_
var arr2 = arr1.slice(); _x000D_
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is_x000D_
                 // deleted not the data pointed by that address_x000D_
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area _x000D_
                 // pointed by the addresses in both arr1 and arr2_x000D_
arr2[1][0] = 9;  // not OK - same above reason_x000D_
_x000D_
console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]_x000D_
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
_x000D_
_x000D_
_x000D_

  1. Solution for 2: Deep Copy by element by element

_x000D_
_x000D_
var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];_x000D_
arr2 = JSON.parse(JSON.stringify(arr1));_x000D_
arr2.pop();   // OK - don't affect arr1_x000D_
arr2[0].x = 'z';  // OK - don't affect arr1_x000D_
arr2[1][0] = 9;   // OK - don't affect arr1_x000D_
_x000D_
console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]_x000D_
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
_x000D_
_x000D_
_x000D_


Just writting:

arr2 = arr1.concat();

You are generating new a new array with a copy of the first. Be aware that is a functional way to push an element into the array.

If your code is based on ES6 you can use spread operator as well:

arr2 = [...arr1];

I personally think Array.from is a more readable solution. By the way, just beware of its browser support.

_x000D_
_x000D_
// clone
let x = [1, 2, 3];
let y = Array.from(x);
console.log({y});

// deep clone
let clone = arr => Array.from(arr, item => Array.isArray(item) ? clone(item) : item);
x = [1, [], [[]]];
y = clone(x);
console.log({y});
_x000D_
_x000D_
_x000D_


For ES6 array containing objects

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}

From ES2015,

var arr2 = [...arr1];

As we know in Javascript arrays and objects are by reference, but what ways we can do copy the array without changing the original array later one?

Here are few ways to do it:

Imagine we have this array in your code:

var arr = [1, 2, 3, 4, 5];

1) Looping through the array in a function and return a new array, like this:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) Using slice method, slice is for slicing part of the array, it will slice some part of your array without touching the original, in the slice, if don't specify the start and end of the array, it will slice the whole array and basically make a full copy of the array, so we can easily say:

var arr2 = arr.slice(); // make a copy of the original array

3) Also contact method, this is for merging two array, but we can just specify one of arrays and then this basically make a copy of the values in the new contacted array:

var arr2 = arr.concat();

4) Also stringify and parse method, it's not recommended, but can be an easy way to copy Array and Objects:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Array.from method, this is not widely supported, before use check the support in different browsers:

const arr2 = Array.from(arr);

6) ECMA6 way, also not fully supported, but babelJs can help you if you want to transpile:

const arr2 = [...arr];

If you want to make a new copy of an object or array, you must explicitly copy the properties of the object or the elements of the array, for example:

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

You can search for more information on Google about immutable primitive values and mutable object references.


Primitive values are always pass by its value (copied). Compound values however are passed by reference.

So how do we copy this arr?

let arr = [1,2,3,4,5];

Copy an Array in ES6

let arrCopy = [...arr]; 

Copy n Array in ES5

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

Why `let arrCopy = arr` is not passing by value?

Passing one varible to another on Compound values such as Object/Array behave difrently. Using asign operator on copand values we pass reference to an object. This is why the value of both arrays are changing when removing/adding arr elements.

Exceptions:

arrCopy[1] = 'adding new value this way will unreference';

When you assign a new value to the variable, you are changing the reference itself and it doesn’t affect the original Object/Array.

read more


Here's a variant:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */

There's the newly introduced Array.from, but unfortunately, as of the time of this writing it's only supported on recent Firefox versions (32 and higher). It can be simply used as follows:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

Reference: Here

Or Array.prototype.map may be used with an identity function:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

Reference: Here


Important!

Most of answers here works for particular cases.

If you don't care about deep/nested objects and props use (ES6):

let clonedArray = [...array]

but if you want to do deep clone use this instead:

let cloneArray = JSON.parse(JSON.stringify(array))


For lodash users:

let clonedArray = _.clone(array) documentation

and

let clonedArray = _.cloneDeep(array) documentation


If your array contains elements of the primitive data type such as int, char, or string etc then you can user one of those methods which returns a copy of the original array such as .slice() or .map() or spread operator(thanks to ES6).

new_array = old_array.slice()

or

new_array = old_array.map((elem) => elem)

or

const new_array = new Array(...old_array);

BUT if your array contains complex elements such as objects(or arrays) or more nested objects, then, you will have to make sure that you are making a copy of all the elements from the top level to the last level else reference of the inner objects will be used and that means changing values in object_elements in new_array will still affect the old_array. You can call this method of copying at each level as making a DEEP COPY of the old_array.

For deep copying, you can use the above-mentioned methods for primitive data types at each level depending upon the type of data or you can use this costly method(mentioned below) for making a deep copy without doing much work.

var new_array = JSON.parse(JSON.stringify(old_array));

There are a lot of other methods out there which you can use depending on your requirements. I have mentioned only some of those for giving a general idea of what happens when we try to copy an array into the other by value.


Here are few more way to copy:

_x000D_
_x000D_
const array = [1,2,3,4];_x000D_
_x000D_
const arrayCopy1 = Object.values(array);_x000D_
const arrayCopy2 = Object.assign([], array);_x000D_
const arrayCopy3 = array.map(i => i);_x000D_
const arrayCopy4 = Array.of(...array );
_x000D_
_x000D_
_x000D_


In my particular case I needed to ensure the array remained intact so this worked for me:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}

Dan, no need to use fancy tricks. All you need to do is make copy of arr1 by doing this.

_x000D_
_x000D_
var arr2 = new Array(arr1);
_x000D_
_x000D_
_x000D_

Now arr1 and arr2 are two different array variables stored in separate stacks. Check this out on jsfiddle.


let a = [1,2,3];

Now you can do any one of the following to make a copy of an array.

let b = Array.from(a); 

OR

let b = [...a];

OR

let b = new Array(...a); 

OR

let b = a.slice(); 

OR

let b = a.map(e => e);

Now, if i change a,

a.push(5); 

Then, a is [1,2,3,5] but b is still [1,2,3] as it has different reference.

But i think, in all the methods above Array.from is better and made mainly to copy an array.


In Javascript, deep-copy techniques depend on the elements in an array. Let's start there.

Three types of elements

Elements can be: literal values, literal structures, or prototypes.

// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';

// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};

// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); // or `new function () {}`

From these elements we can create three types of arrays.

// 1) Array of literal-values (boolean, number, string) 
const type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
const type2 = [[], {}];

// 3) Array of prototype-objects (function)
const type3 = [function () {}, function () {}];

Deep copy techniques depend on the three array types

Based on the types of elements in the array, we can use various techniques to deep copy.

Javascript deep copy techniques by element types

  • Array of literal-values (type1)
    The [...myArray], myArray.splice(0), myArray.slice(), and myArray.concat() techniques can be used to deep copy arrays with literal values (boolean, number, and string) only; where the Spread operator [...myArray] has the best performance (https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat).

  • Array of literal-values (type1) and literal-structures (type2)
    The JSON.parse(JSON.stringify(myArray)) technique can be used to deep copy literal values (boolean, number, string) and literal structures (array, object), but not prototype objects.

  • All arrays (type1, type2, type3)
    The jQuery $.extend(myArray) technique can be used to deep-copy all array-types. Libraries like Underscore and Lo-dash offer similar deep-copy functions to jQuery $.extend(), yet have lower performance. More surprisingly, $.extend() has higher performance than the JSON.parse(JSON.stringify(myArray)) technique http://jsperf.com/js-deep-copy/15.
    And for those developers that shy away from third-party libraries (like jQuery), you can use the following custom function; which has higher performance than $.extend, and deep-copies all arrays.

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

So to answer the question...

Question

var arr1 = ['a','b','c'];
var arr2 = arr1;

I realized that arr2 refers to the same array as arr1, rather than a new, independent array. How can I copy the array to get two independent arrays?

Answer

Because arr1 is an array of literal values (boolean, number, or string), you can use any deep copy technique discussed above, where the spread operator ... has the highest performance.

// Highest performance for deep copying literal values
arr2 = [...arr1];

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.slice();
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above

Adding to the solution of array.slice(); be aware that if you have multidimensional array sub-arrays will be copied by references. What you can do is to loop and slice() each sub-array individually

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

same things goes to array of objects, they will be copied by reference, you have to copy them manually


You can use array spreads ... to copy arrays.

const itemsCopy = [...items];

Also if want to create a new array with the existing one being part of it:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

Array spreads are now supported in all major browsers but if you need older support use typescript or babel and compile to ES5.

More info on spreads