在javascript中将对象数组复制到另一个数组中(Deep Copy)

时间:2015-02-12 16:25:49

标签: javascript arrays node.js google-chrome deep-copy

使用slice(0)和concat()在javascript中将对象数组复制到另一个数组中不起作用。

我已经尝试过以下测试是否可以使用此方法获得深层复制的预期行为。但是,在复制的数组中进行更改后,原始数组也会被修改。

var tags = [];
for(var i=0; i<3; i++) {
    tags.push({
        sortOrder: i,
        type: 'miss'
    })
}
for(var tag in tags) { 
    if(tags[tag].sortOrder == 1) {
        tags[tag].type = 'done'
    }
}
console.dir(tags)

var copy = tags.slice(0)
console.dir(copy)

copy[0].type = 'test'
console.dir(tags)

var another = tags.concat()
another[0].type = 'miss'
console.dir(tags)

如何将数组的深层副本复制到另一个数组中,以便在复制数组中进行更改时不会修改原始数组。

9 个答案:

答案 0 :(得分:67)

尝试

var copy = JSON.parse(JSON.stringify(tags));

答案 1 :(得分:14)

尝试以下

// Deep copy
var newArray = jQuery.extend(true, [], oldArray);

有关详细信息,请查看此问题What is the most efficient way to deep clone an object in JavaScript?

答案 2 :(得分:4)

如上所述, Here .slice(0)可以有效地使用基本类型元素克隆数组。但是在您的示例中,tags数组包含匿名对象。因此,克隆数组中对这些对象的任何更改都会反映在tags数组中。

@ dangh上面的回复derefences这些元素对象并创建新的元素。

Here is another thread 解决类似情况

答案 3 :(得分:2)

使用ES6克隆对象数组的一种好方法是使用扩展语法:

const clonedArray = [...oldArray];

MDN

答案 4 :(得分:1)

您只需要使用'...'符号即可。

// THE FOLLOWING LINE COPIES all elements of 'tags' INTO 'copy'
var copy = [...tags]

当您有一个数组时,说x,[... x]创建一个包含所有x值的新数组。请注意,因为此符号在对象上的作用略有不同。它将对象划分为其所有键,值对。因此,如果要将对象的所有键值对传递给函数,则只需要传递function({... obj})

答案 5 :(得分:0)

使用Underscore / Lodash

在一行中最容易和乐观的方式
  

让a = _.map(b,_.clone)

答案 6 :(得分:0)

同样的问题发生在我身上。我有来自服务的数据并保存到另一个变量。当我更新我的数组时,复制的数组也会更新。旧代码如下所示

//$scope.MyData get from service
$scope.MyDataOriginal = $scope.MyData;

因此,当我更改$ scope.MyData时,也会更改$ scope.MyDataOriginal。 我找到了一个解决方案,angular.copy正确的代码如下

$scope.MyDataOriginal = angular.copy($scope.MyData);

答案 7 :(得分:0)

我知道这是一篇比较老的文章,但是我很幸运地找到了一种不错的方法来深度复制数组,即使是那些包含数组和对象的对象,甚至是包含数组的对象都被复制了……我只能看到此代码的一个问题是,如果您没有足够的内存,我会在非常大的数组和对象数组上看到这种窒息现象……但是在大多数情况下,它应该可以工作。我在此处发布此消息的原因是,它完成了OP请求,即按值而不是按引用复制对象数组...因此现在使用代码(检查来自SO,即我编写的​​主要复制函数,而不是也许其他人以前没有写过,我只是不知道它们):

var isArray = function(a){return (!!a) && (a.constructor===Array);}
var isObject = function(a){return (!!a) && (a.constructor===Object);}
Array.prototype.copy = function(){
    var newvals=[],
        self=this;
    for(var i = 0;i < self.length;i++){
        var e=self[i];
        if(isObject(e)){
            var tmp={},
                oKeys=Object.keys(e);
            for(var x = 0;x < oKeys.length;x++){
                var oks=oKeys[x];
                if(isArray(e[oks])){
                    tmp[oks]=e[oks].copy();
                } else { 
                    tmp[oks]=e[oks];
                }
            }
            newvals.push(tmp);
        } else {
            if(isArray(e)){
                newvals.push(e.copy());
            } else {
                newvals.push(e);
            }
        }
    }
    return newvals;
}

当调用对象或数组以根据需要返回值时,此函数(Array.prototype.copy)使用递归自身进行调用。该过程非常快,并且可以按照您的意愿进行操作,可以对数组进行深度复制(按值)...在chrome和IE11中进行了测试,并且可以在这两种浏览器中使用。

答案 8 :(得分:-1)

为此,我使用新的ECMAScript 6 Object.assign方法:

let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject)

此方法的第一个参数是要更新的数组, 我们传递一个空对象,因为我们想要一个全新的对象,

您也可以添加其他要复制的对象:

let newObject = Object.assign({}, oldObject, o2, o3, ...)