将JavaScript中的数组复制到另一个数组时:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
我意识到arr2指的是与arr1相同的数组,而不是一个新的独立数组。如何复制阵列以获得两个独立的阵列?
将JavaScript中的数组复制到另一个数组时:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
我意识到arr2指的是与arr1相同的数组,而不是一个新的独立数组。如何复制阵列以获得两个独立的阵列?
当前回答
快速示例:
如果数组中的元素是基元类型(字符串、数字等)
var arr1=[‘a’,‘b’,‘c’];//arr1和arr2是独立的,基本元素存储在//记忆中的不同位置var arr2=arr1.slice();arr2.推('d');console.log(arr1);//[“a”、“b”、“c”]console.log(arr2);//[“a”、“b”、“c”、“d”]
如果数组中的元素是对象文本,则另一个数组({},[])
var arr1=[{x:'a',y:'b'},[1,2],[3,4]];//arr1和arr2是独立的,引用的/地址存储在不同的//记忆中的位置。但这些参考文献/地址指向了一些共同的地方//在存储器中。var arr2=arr1.slice();arr2.pop();//好-不影响arr1 bcos,只有arr2中的地址是//删除的不是该地址所指向的数据arr2[0].x=“z”;//不正常-影响在公共区域进行的arr1 bcos更改//由arr1和arr2中的地址指示arr2[1][0]=9;//不正常-与上述原因相同console.log(arr1);//[{x:'z',y:'b'},[9,2],[3,4]]console.log(arr2);//[{x:'z',y:'b'},[9,2]]
解决方案2:逐元素深度复制
var arr1=[{x:'a',y:'b'},[1,2],[3,4]];arr2=JSON.parse(JSON.stringify(arr1));arr2.pop();//OK-不影响arr1arr2[0].x=“z”;//好-不影响arr1arr2[1][0]=9;//OK-不影响arr1console.log(arr1);//[{x:“a”,y:“b”},[1,2],[3,4]]console.log(arr2);//[{x:'z',y:'b'},[9,2]]
其他回答
切片的另一种选择是凹面,可以用两种方式。第一个可能更容易理解,因为预期行为非常清楚:
var array2 = [].concat(array1);
第二种方法是:
var array2 = array1.concat();
科恩(在评论中)指出,后一种方法具有更好的性能。
其工作方式是concat方法创建一个新数组,该数组由调用它的对象中的元素组成,后跟作为参数传递给它的任何数组的元素。因此,当没有传递参数时,它只是复制数组。
Lee Penkman也在评论中指出,如果array1有可能未定义,可以返回一个空数组,如下所示:
var array2 = [].concat(array1 || []);
或者,对于第二种方法:
var array2 = (array1 || []).concat();
请注意,您也可以使用slice:var array2=(array1||[]).slice();执行此操作;。
如果要创建对象或数组的新副本,必须显式复制对象或数组元素的财产,例如:
var arr1 = ['a','b','c'];
var arr2 = [];
for (var i=0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}
您可以在Google上搜索有关不可变原始值和可变对象引用的更多信息。
您可以将ES6与spread Opartor一起使用,它更简单。
arr2 = [...arr1];
有一些限制。。check docs Spread语法@mozilla
其中一些方法在处理简单的数据类型(如数字或字符串)时工作得很好,但当数组包含其他对象时,这些方法会失败。当我们试图将任何对象从一个数组传递到另一个数组时,它将作为引用传递,而不是对象。
在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))(大量开销)。
源性能测试