按值复制数组

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

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

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

JinJin宝儿2020/03/09 19:54:33

对于包含对象的ES6数组

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}
逆天伽罗宝儿2020/03/09 19:54:33

有新引入的Array.from,但不幸的是,截至撰写本文时,它仅在最新的Firefox版本(32及更高版本)上受支持。它可以简单地如下使用:

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

参考:这里

或者Array.prototype.map可以与身份功能一起使用:

function identity(param)
{
    return param;
}

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

参考:这里

猴子小哥2020/03/09 19:54:33

您可以将ES6与更简单的传播Opeartor一起使用。

arr2 = [...arr1];

有限制..check docs @mozilla 传播语法

路易Itachi2020/03/09 19:54:33

以下是几种复制方式:

const array = [1,2,3,4];

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

古一斯丁猴子2020/03/09 19:54:33

您还可以使用ES6传播运算符复制Array

var arr=[2,3,4,5];
var copyArr=[...arr];
ASamJim2020/03/09 19:54:33

使用jQuery深度复制可以如下进行:

var arr2 = $.extend(true, [], arr1);
Jnck2020/03/09 19:54:33

如果您的数组包含原始数据类型的元素(例如int,char或string等),则可以使用这些方法之一,这些方法返回原始数组的副本,例如.slice()或.map()或散布运算符(感谢ES6)。

new_array = old_array.slice()

要么

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

要么

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

但是,如果您的数组包含复杂的元素(例如对象(或数组)或更多嵌套对象),则必须确保要复制从顶层到最后一层的所有元素,否则要复制内部元素将使用对象,这意味着更改new_array中的object_elements中的值仍会影响old_array。您可以像 对old_array 进行DEEP COPY一样在每个级别调用这种复制方法

对于深度复制,您可以根据数据类型在每个级别上对原始数据类型使用上述方法,也可以使用这种昂贵的方法(如下所述)进行深度复制而无需做很多工作。

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

您还可以根据需要使用许多其他方法。我只提到了其中的一些,以便大致了解当我们尝试按值将数组复制到另一个数组时会发生什么

路易伽罗2020/03/09 19:54:33

我个人更喜欢这样:

JSON.parse(JSON.stringify( originalObject ));
小小前端2020/03/09 19:54:33

丹,无需花哨的技巧。您需要做的就是通过这样做来复制arr1。

var arr2 = new Array(arr1);

现在arr1arr2是两个不同的数组变量,分别存储在单独的堆栈中。 在jsfiddle上检查一下

阿飞小哥2020/03/09 19:54:33
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.push(5); 

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

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

梅Harry2020/03/09 19:54:33

在我的特定情况下,我需要确保阵列保持完整,因此这对我有用:

// 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]);
}
LEYJim2020/03/09 19:54:33

正如我们在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是对数组的一部分进行切片,它将在不触摸原始数组的情况下对数组的一部分进行切片,如果未指定数组的开始和结尾,则会对整个数组进行切片数组,并基本上制作该数组的完整副本,因此我们可以轻松地说:

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

3)也是接触方法,这是用于合并两个数组的方法,但是我们可以只指定一个数组,然后基本上复制新的接触数组中的值:

var arr2 = arr.concat();

4)还是stringify和parse方法,不建议这样做,但是它可以是复制Array和Objects的简单方法:

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

5)Array.from方法,不被广泛​​支持,使用前请在不同的浏览器中检查支持:

const arr2 = Array.from(arr);

6)ECMA6方式,也不完全受支持,但是babelJs可以帮助您进行移植:

const arr2 = [...arr];
Eva2020/03/09 19:54:33

添加到array.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]);

相同的处理对象数组,它们将通过引用复制,您必须手动复制它们

卡卡西十三2020/03/09 19:54:33

重要!

这里的大多数答案适用于特定情况

如果您不关心深层/嵌套对象和道具,请使用(ES6):

let clonedArray = [...array]

但是,如果要进行深度克隆,请改用以下方法:

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


对于lodash用户:

let clonedArray = _.clone(array) 文件资料

let clonedArray = _.cloneDeep(array) 文件资料

GOL蛋蛋2020/03/09 19:54:33

从ES2015开始,

var arr2 = [...arr1];
古一凯Gil2020/03/09 19:54:33

我个人认为Array.from是一个更具可读性的解决方案。顺便提一下,请注意它的浏览器支持。

//clone
let x = [1,2,3];
let y = Array.from(x);

//deep clone
let clone = arr => Array.from(arr,item => Array.isArray(item) ? clone(item) : item);
let x = [1,[],[[]]];
let y = clone(x);
Tom阿飞2020/03/09 19:54:33

在尝试了多种方法之后,我就是这样做的:

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 ...)

Mandy村村Harry2020/03/09 19:54:33

不需要jQuery ... 工作示例

var arr2 = arr1.slice()

这将从数组的起始位置复制到数组0的末尾。

重要的是要注意,它将对基本类型(字符串,数字等)正常工作,并解释引用类型的预期行为...

如果您有一组引用类型,请说type Object该数组被复制,但是两个数组都将包含对相同数组的引用Object因此,在这种情况下,即使实际复制了数组,也似乎是通过引用复制了该数组

Harry泡芙2020/03/09 19:54:33

的替代方法sliceconcat,可以使用2种方法。由于预期的行为非常明确,因此第一个可能更易读:

var array2 = [].concat(array1);

第二种方法是:

var array2 = array1.concat();

科恩(在评论中)指出,后一种方法具有更好的性能

这种方法的工作方式是,该concat方法创建一个新数组,该数组由调用它的对象中的元素组成,然后是作为参数传递给它的任何数组的元素。因此,当不传递任何参数时,它仅复制数组。

李Penkman,也是在评论中指出,如果有一个机会array1undefined,你可以按照如下返回一个空数组:

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

或者,对于第二种方法:

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

需要注意的是,你还可以这样做slicevar array2 = (array1 || []).slice();

Davaid神奇Eva2020/03/09 19:54:33

用这个:

var newArray = oldArray.slice();

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

另请注意:

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

字符串和数字之类的基元是不可变的,因此无法更改字符串或数字。