【问题标题】:Copying an array of objects into another array in javascript (Deep Copy)在javascript中将对象数组复制到另一个数组中(深度复制)
【发布时间】:2015-04-13 11:47:12
【问题描述】:

使用 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)

如何将一个数组深度复制到另一个数组中,这样如果我对复制数组进行更改,原始数组就不会被修改。

【问题讨论】:

  • 我不确定您要做什么,但是。我建议将您的第二个 for 循环更改为 for of 循环 for of(var tag of tags) { if(tag.sortOrder == 1) { tag.type == 'done' }}
  • 根据你的环境,你可以试试 Object.create?
  • @zlatko 你能举个同样的例子吗
  • 哦,var newObject = Object.create(oldObject) 应该给你一个基于 proto 的旧对象的取消引用克隆。不知道阵列,买你可以试试。评论的环境部分是我不知道你是在使用 V8 还是其他 JS 引擎,我认为它不是到处都支持(但有 polyfils)。

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


【解决方案1】:

您只需要使用“...”符号。

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

当你有一个数组说 x 时,[...x] 创建一个包含所有 x 值的新数组。请小心,因为此符号在对象上的工作方式略有不同。它将对象拆分为所有的键、值对。所以如果你想将一个对象的所有键值对传递给一个函数,你只需要传递 function({...obj})

【讨论】:

  • 他需要深拷贝,而不是浅拷贝。
  • 这不会导致深拷贝,新数组中的对象仍将引用旧数组中的对象
  • 哦,好的。对不起
【解决方案2】:

我知道这是一个较旧的帖子,但我有幸找到了一种体面的方法来深度复制数组,即使是包含数组和对象的数组,甚至包含数组的对象也会被复制......我只能看到这段代码的一个问题是,如果你没有足够的内存,我可以看到这种阻塞在非常大的数组和对象数组上......但在大多数情况下它应该可以工作。我在此处发布此内容的原因是它完成了按值而不是按引用复制对象数组的 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 中进行了测试,并且可以在这两个浏览器中使用。

【讨论】:

    【解决方案3】:

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

    const clonedArray = [...oldArray];
    

    MDN

    【讨论】:

    • 这是浅拷贝
    【解决方案4】:

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

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

    所以每当我更改 $scope.MyData 时,也会更改 $scope.MyDataOriginal。 我找到了 angular.copy right 代码如下的解决方案

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

    【讨论】:

      【解决方案5】:

      在一行中执行此操作的最简单和最乐观的方法是使用 Underscore/Lodash

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

      【讨论】:

        【解决方案6】:

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

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

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

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

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

        【讨论】:

        • 即使使用 Object.assign 你也有同样的问题,现在存在于 Javascript 中的每个方法都适用于原语,如果你的对象的键具有另一个对象的值,引用将被保留
        【解决方案7】:

        试试下面的

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

        欲了解更多详情,请查看此问题What is the most efficient way to deep clone an object in JavaScript?

        【讨论】:

        • 这不起作用,因为结果是一个对象,而不是一个数组。
        【解决方案8】:

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

        @dangh 上面的回复取消了这些元素对象的引用并创建了新对象。

        Here is another thread解决类似情况

        【讨论】:

          【解决方案9】:

          试试

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

          【讨论】:

          • 超过半岁,仍然有帮助!
          • @Aerious 好吧,这行得通,因为您将数组/对象序列化为字符串。当您解析该字符串时,会实例化全新的对象,就好像您从某个 api 接收到有效负载一样。但是没有保留引用,所以如果你有指向其他元素的数组元素,这将是危险的。
          • @SavaB。同意:)
          • 请记住,如果数组中的任何对象(标签)是循环结构,它就不起作用,这意味着它间接引用了自己。这种情况最终会出现“TypeError: Converting circular structure to JSON”错误。
          猜你喜欢
          • 2015-04-13
          • 2013-04-20
          • 2012-04-10
          • 2015-05-06
          • 2013-05-28
          • 2014-11-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多