复制数组的值

2123

在 JavaScript 中将一个数组复制到另一个数组时:

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

我意识到 arr2 指的是与 arr1 相同的数组,而不是一个新的独立数组。如何将数组复制以获得两个独立的数组?

4
在Chrome 53和Firefox 48中,slicesplice操作的性能表现很好,而新的扩展运算符和Array.from的实现则比较慢。可参考perfjs.fnfo - Pencroff
https://jsperf.com/flat-array-copy - Walle Cyril
对于包含原始字符串的数组,您可以使用 var arr2 = arr1.splice(); 进行深度复制,但是如果您的数组元素包含文字结构(即 []{})或原型对象(即 function () {}new 等),则此技术将无法工作。请参见下面的答案以获取更多解决方案。 - tim-montague
41
2017年了,你可以考虑使用ES6的特性:let arr2 = [...arr1];。详见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator。 - Hinrich
2
当你声明 a = b; 时,实际上是告诉程序在随机访问内存中指向同一个符号链接。当更改此符号链接处的值时,会影响到 ab... 因此,如果你使用扩展运算符 a= [...b];,程序将创建一个额外的符号链接到随机访问内存中的不同位置,然后你可以独立地操作 ab - 71GA
显示剩余3条评论
40个回答

12

如果你处于 ECMAScript 6 环境中,可以使用 扩展运算符 来完成此操作:

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

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>


12

原始值始终按其值(复制)进行传递。然而,复合值通过引用传递。

那么我们如何复制这个 arr ?

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

在ES6中复制一个数组

let arrCopy = [...arr]; 

在ES5中复制n个数组

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

为什么 `let arrCopy = arr` 不是按值传递?

在复合值(如对象/数组)中将一个变量传递给另一个变量的行为是不同的。使用赋值运算符在复合值上,我们会传递一个指向对象的引用。这就是为什么在删除/添加arr元素时,两个数组的值都会发生变化。

例外情况:

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

当你将一个新的值赋给变量时,你正在改变引用本身,这不会影响原始的对象/数组。

阅读更多


9

在解决 array.slice(); 问题时,需要注意如果你有多维数组,子数组将通过引用进行复制。你可以循环并逐个切片(slice())每个子数组。

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]);

同样的道理也适用于对象数组,它们将被引用复制,您需要手动复制它们。


这个回答应该在页面顶部获得一个位置!我正在处理多维子数组,但不明白为什么内部数组总是通过引用而不是值进行复制。这个简单的逻辑解决了我的问题。如果可能的话,我会给你+100分! - Mac

8
let a = [1,2,3];

现在,您可以执行以下任何一项操作来复制数组。
let b = Array.from(a); 

或者

let b = [...a];

或者

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

或者

let b = a.slice(); 

或者

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

现在,如果我改变a的值,
a.push(5); 

然后,a是[1,2,3,5],但b仍然是[1,2,3],因为它有不同的引用。

但我认为,在上述所有方法中Array.from是更好的选择,主要用于复制一个数组。


1
哪一个是最快的? - Marc Frame

8

我个人更喜欢这种方式:

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

那么这里建议的方式是什么?(链接:https://dev59.com/rWs05IYBdhLWcg3wCNlG#23536726) - Script47

8

我发现这种方法相对较容易:

let arr = [1,2,3,4,5];
let newArr = [...arr];
console.log(newArr);


这个问题已经在这里得到了回答(以及其他一些答案)。 - Ivar

7

当有大量答案时,您必须使用最佳实践来回答此问题。

我建议您使用数组展开符(array spreads)来复制数组。

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

var arr2 = […arr1];


5

众所周知,在JavaScript中,数组对象是按引用传递的。那么有什么方法可以复制数组而不改变原始数组吗?

以下是几种方法:

假设在你的代码中有这个数组:

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

1)在函数中循环遍历数组并返回一个新的数组,例如:

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

2) 使用slice方法,slice是用来切割数组的一部分,它将切割数组的一部分而不影响原始数组,在slice中,如果没有指定数组的开始和结束,它将切割整个数组并基本上复制整个数组,因此我们可以轻松地说:

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

3) 另外还有一种联系方法,用于合并两个数组,但我们只需要指定其中一个数组,然后就可以将其值复制到新的联系数组中:

var arr2 = arr.concat();

4) 同样的,字符串化和解析方法并不推荐使用,但可以是复制数组和对象的简单方式:

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

5) Array.from方法,这个方法并不被广泛支持,在使用之前请检查不同浏览器的支持情况:

const arr2 = Array.from(arr);

6) 使用ECMA6的方法,也没有完全支持,但是如果你想要转换,babelJs可以帮助你:

const arr2 = [...arr];

5
丹,不需要使用花哨的技巧。你只需要通过这样做来复制arr1.

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

var arr2 = new Array(arr1);

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

console.log('arr1:');
console.log(arr1);

console.log('arr2:');
console.log(arr2);

// Following did the trick:
var arr3 = [...arr1];
arr3.push('d');  // Now, arr3 = ['a','b','c','d'];

console.log('arr3:');
console.log(arr3);

现在,arr1arr2是存储在不同堆栈中的两个不同的数组变量。 在jsfiddle上查看

3
这不是复制数组,而是创建一个只有一个元素的数组,该元素引用原始数组(即 var arr2 = [arr1];)。 - Timothy003
@DragoRaptor,希望你不介意我编辑了你的答案,将你在jsfiddle中的代码补充到这里,将document.write(arr2)更改为console.log(arr2),以便展示嵌套数组结构并更好地说明@Timothy003的正确评论。不过,var arr3 = [...arr1]就解决了问题。运行代码片段以查看结果。(document.write(arr2)的输出有点误导人,所以我不怪你)。 - Jürgen Fink

5
你可以使用ES6的展开运算符,它更简单易懂。
arr2 = [...arr1];

有一些限制...请查看文档 mozilla上的展开语法


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接