75

如何将数组的每个元素(其中元素是对象)复制到另一个数组中,以使它们完全独立?我不想改变一个数组中的元素来影响另一个。

4

7 回答 7

116

这里的关键是

  1. 数组中的条目是对象,并且
  2. 您不希望对一个数组中的对象的修改显示在另一个数组中。

这意味着我们不仅需要将对象复制到新数组(或目标数组),还需要创建对象的副本

如果目标数组还不存在...

...用于map创建一个新数组,并随时复制对象:

const newArray = sourceArray.map(obj => /*...create and return copy of `obj`...*/);

...复制操作是您喜欢复制对象的任何方式,根据用例,项目之间的差异很大。此问题的答案中深入讨论了该主题。但是例如,如果您只想复制对象而不是其属性引用的任何对象,则可以使用扩展符号(ES2015+):

const newArray = sourceArray.map(obj => ({...obj}));

这对每个对象(和数组)进行了浅拷贝。同样,对于深拷贝,请参阅上面链接的问题的答案。

这是一个使用不尝试处理边缘情况的简单形式的深拷贝的示例,请参阅边缘情况的链接问题:

function naiveDeepCopy(obj) {
    const newObj = {};
    for (const key of Object.getOwnPropertyNames(obj)) {
        const value = obj[key];
        if (value && typeof value === "object") {
            newObj[key] = {...value};
        } else {
            newObj[key] = value;
        }
    }
    return newObj;
}
const sourceArray = [
    {
        name: "joe",
        address: {
            line1: "1 Manor Road",
            line2: "Somewhere",
            city: "St Louis",
            state: "Missouri",
            country: "USA",
        },
    },
    {
        name: "mohammed",
        address: {
            line1: "1 Kings Road",
            city: "London",
            country: "UK",
        },
    },
    {
        name: "shu-yo",
    },
];
const newArray = sourceArray.map(naiveDeepCopy);
// Modify the first one and its sub-object
newArray[0].name = newArray[0].name.toLocaleUpperCase();
newArray[0].address.country = "United States of America";
console.log("Original:", sourceArray);
console.log("Copy:", newArray);
.as-console-wrapper {
    max-height: 100% !important;
}

如果目标数组存在...

...并且您想将源数组的内容附加到它,您可以使用push一个循环:

for (const obj of sourceArray) {
    destinationArray.push(copy(obj));
}

有时人们真的想要“一个班轮”,即使没有特别的理由。如果您引用它,您可以创建一个新数组,然后使用扩展符号将其扩展为单个push调用:

destinationArray.push(...sourceArray.map(obj => copy(obj)));
于 2013-04-26T09:22:36.213 回答
32

让这个工作的简单方法是使用:

var cloneArray = JSON.parse(JSON.stringify(originalArray));

我在获取arr.concat()arr.splice(0)提供深层副本时遇到问题。上面的片段完美地工作。

于 2015-02-12T16:40:08.007 回答
12

克隆数组的一个好方法是使用数组字面量和扩展语法ES2015使这成为可能。

const objArray = [{name:'first'}, {name:'second'}, {name:'third'}, {name:'fourth'}];

const clonedArr = [...objArray];

console.log(clonedArr) // [Object, Object, Object, Object]

您可以在 MDN 的文档中找到此复制选项:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Copy_an_array

这也是Airbnb 的最佳实践。https://github.com/airbnb/javascript#es6-array-spreads

注意:ES2015 中的扩展语法在复制数组时会加深一层。因此,它们不适合复制多维数组。

于 2017-03-27T20:46:48.550 回答
5
var clonedArray = array.concat();
于 2013-04-26T09:27:29.593 回答
2

如果您想保留参考:

Array.prototype.push.apply(destinationArray, sourceArray);

于 2016-04-20T18:02:24.027 回答
1

有两个重要的注意事项。

  1. 使用array.concat()Angular 1.4.4 和 jQuery 3.2.1 (这是我的环境)不起作用。
  2. array.slice(0)一个对象。因此,如果您执行类似newArray1 = oldArray.slice(0); newArray2 = oldArray.slice(0)的操作,两个新数组将仅引用 1 个数组,而更改一个数组将影响另一个数组。

或者, usingnewArray1 = JSON.parse(JSON.stringify(old array))只会复制该值,因此每次都会创建一个新数组。

于 2017-08-22T09:28:14.680 回答
0

concat()如果您使用的是 nodeJS,我建议使用。在所有其他情况下,我发现slice(0)效果很好。

于 2014-12-11T07:34:02.173 回答