Copy array by value

2018-12-30 23:21发布

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?

30条回答
若你有天会懂
2楼-- · 2018-12-31 00:00

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:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

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:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

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:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

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:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

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

查看更多
刘海飞了
3楼-- · 2018-12-31 00:00

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

查看更多
何处买醉
4楼-- · 2018-12-31 00:01

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]);
}
查看更多
后来的你喜欢了谁
5楼-- · 2018-12-31 00:01

Using jQuery deep copy could be made as following:

var arr2 = $.extend(true, [], arr1);
查看更多
心情的温度
6楼-- · 2018-12-31 00:01

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.

查看更多
临风纵饮
7楼-- · 2018-12-31 00:01

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
 */
查看更多
登录 后发表回答