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

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

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


当前回答

其中一些方法在处理简单的数据类型(如数字或字符串)时工作得很好,但当数组包含其他对象时,这些方法会失败。当我们试图将任何对象从一个数组传递到另一个数组时,它将作为引用传递,而不是对象。

在JavaScript文件中添加以下代码:

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;
};

只需使用

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

这会奏效的。

其他回答

当我们想要使用赋值运算符(=)复制数组时,它不会创建副本,只会复制指向数组的指针/引用。例如:

常量oldArr=[1,2,3];const newArr=旧Arr;//现在oldArr指向内存中的相同位置console.log(oldArr==newArr);//指向内存中的相同位置,因此是正确的常量拷贝=[1,2,3];console.log(copy==newArr);//不指向内存中的相同位置,因此是错误的

通常,当我们转换数据时,我们希望保持初始数据结构(例如数组)的完整性。我们通过制作数组的精确副本来实现这一点,这样可以在初始数组保持不变的情况下转换该数组。

复制阵列的方法:

常量oldArr=[1,2,3];//使用扩展运算符将旧值扩展到新数组文本中const newArr1=[…oldArr];//不带参数的切片返回新复制的数组const newArr2=oldArr.slice();//Map将回调应用于数组中的每个元素并返回一个新数组const newArr3=旧Arr.map((el)=>el);//Concat用于合并数组并返回一个新数组。不带参数的凹形复制数组const newArr4=oldArr.contat();//Object.assign可用于将所有财产转换为新的数组文字const newArr5=对象赋值([],oldArr);//使用new关键字通过Array构造函数创建const newArr6=新数组(…oldArr);//For循环函数克隆(基本){常量newArray=[];for(设i=0;i<base.length;i++){newArray[i]=基[i];}return newArray;}const newArr7=克隆(oldArr);console.log(newArr1、newArr2、newArr3、newArr4、newArr5、newArr6、newArr7);

嵌套数组或对象时要小心!:

嵌套数组时,将通过引用复制值。以下是一个示例,说明这可能会导致问题:

设arr1=[1,2,[1,2]]设arr2=[…arr1];arr2[2][0]=5;//我们改变arr2console.log(arr1);//arr1也被更改,因为arr1内部的数组是通过引用复制的

因此,当数组中存在要复制的对象或数组时,不要使用这些方法。即,仅在基元数组上使用这些方法。

如果您确实想深度克隆javascript数组,请将JSON.parse与JSON.stringify结合使用,如下所示:

设arr1=[1,2,[1,2]]让arr2=JSON.parse(JSON.stringify(arr1));arr2[2][0]=5;console.log(arr1);//现在我没有被修改,因为我是一个深度克隆

复制性能:

因此,我们选择哪一种来获得最佳性能。结果证明,最冗长的方法,for循环具有最高的性能。使用for循环进行真正的CPU密集型复制(大/多阵列)。

在此之后,.slice()方法也有不错的性能,而且不那么冗长,程序员更容易实现。我建议将.slice()用于日常复制不太占用CPU的数组。如果不需要深度克隆,并且性能存在问题,还应避免使用JSON.parse(JSON.stringify(arr))(大量开销)。

源性能测试

只是在写:

arr2 = arr1.concat();

您正在使用第一个数组的副本生成新数组。请注意,这是将元素推入数组的一种功能方式。

如果您的代码基于ES6,您也可以使用扩展运算符:

arr2 = [...arr1];

在研究之后,我发现一个干净的方法可以是:

  const arr1 = [['item 1-1', 'item 1-2'], ['item 2-1', 'item 2-2'], ['item 3-1', 'item 3-2']];

  /**
   * Using Spread operator, it will create a new array with no reference to the first level.
   * 
   * Since, the items are not primitive, they get their own references. It means that any change on them,
   * it will be still reflected on the original object (aka arr1).
   */
  const arr2 = [...arr1];

  /**
   * Using Array.prototype.map() in conjunction Array.prototype.slice() will ensure:
   * - The first level is not a reference to the original array.
   * - In the second level, the items are forced (via slice()) to be created as new ones, so there is not reference to the original items
   */
  const arr3 = arr1.map(item => item.slice());

您需要了解要使用的阵列的复杂性,然后应用最佳解决方案(即➡️ 引用数组中的引用项)

使用此项:

让oldArray=[1,2,3,4,5];let newArray=oldArray.slice();console.log({newArray});

基本上,slice()操作克隆数组并返回对新数组的引用。

还应注意:

对于引用、字符串和数字(而不是实际对象),slice()将对象引用复制到新数组中。原始数组和新数组都引用同一对象。如果引用的对象发生更改,则这些更改对新阵列和原始阵列都可见。

字符串和数字等基元是不可变的,因此不可能更改字符串或数字。

您可以将ES6与spread Opartor一起使用,它更简单。

arr2 = [...arr1];

有一些限制。。check docs Spread语法@mozilla