在javascript中将对象数组复制到另一个数组而没有对象引用(深拷贝)

Posted

技术标签:

【中文标题】在javascript中将对象数组复制到另一个数组而没有对象引用(深拷贝)【英文标题】:Copying of an array of objects to another Array without object reference in javascript(Deep copy) 【发布时间】:2012-04-10 18:21:35 【问题描述】:

我有一个场景,我需要将对象数组(主数组)复制到另一个临时数组,如果我对主数组进行任何修改,它基本上不应该有对象引用,它不应该反映在临时数组中,这样我将独立保存副本。

我使用了堆栈溢出中的代码 sn-p 之一,这部分类似于如果我从主数组中删除所有对象,临时数组仍然保留该值,但是当我在主数组中进行一些修改并单击取消按钮时我正在使用 array.Removeall() 从主数组中删除所有对象;但修改仍然存在于 Temp 数组中,因此这意味着该对象具有引用。

clone: function (existingArray) 
  var newObj = (existingArray instanceof Array) ? [] : ;
  console.debug('newObj value is ' + newObj);
  for (i in existingArray) 
    console.debug('i value is' + i);
    if (i == 'clone') continue;
    console.debug('existingArray[i] value ' + existingArray[i]);
    if (existingArray[i] && typeof existingArray[i] == "object") 

      newObj[i] = this.clone(existingArray[i]);
     else 
      console.debug('in else part ' + existingArray[i]);
      newObj[i] = existingArray[i];
    
  
  return newObj;

我的对象结构是这样的

我正在使用淘汰赛框架。

newObjectCreation = function (localIp, RemoteIp, areaId) 
  this.localIP = ko.observable(localIp);
  this.remoteIP = ko.observable(RemoteIp);
  this.areaId = ko.observable(areaId);
;

template.ProtocolArray.push(new newObjectCreation('', '', '')); // to create default row

请在这方面帮助我。 提前致谢。

【问题讨论】:

对象是否包含无法表达为JSON(不是对象文字)的任何内容?如果没有,你可以简单地做:var clone = JSON.parse(JSON.stringify(src)); 相关:***.com/questions/122102/… Copying array by value in javascript的可能重复 【参考方案1】:

让我明白:您不希望只拥有一个新数组,而是希望为数组本身中存在的所有对象创建一个新实例?那么如果你修改了 temp 数组中的一个对象,那么这些更改不会传播到主数组吗?

如果是这种情况,则取决于您保留在主数组中的值。如果这些对象是简单对象,并且可以用JSON序列化,那么最快的方法是:

var tempArray = JSON.parse(JSON.stringify(mainArray));

如果您有更复杂的对象(例如由您自己的构造函数、html 节点等创建的实例),那么您需要一种特殊的方法。

编辑:

如果您的newObjectCreation 上没有任何方法,您可以使用JSON,但构造函数不会相同。否则你必须手动复制:

var tempArray = [];
for (var i = 0, item; item = mainArray[i++];) 
    tempArray[i] = new newObjectCreation(item.localIP, item.remoteIP, item.areaId);

【讨论】:

所以 var tempArray = JSON.parse(JSON.stringify(mainArray));做一个深拷贝,即没有对象引用? 2.)关于手动复制,此手动复制是否仍指向相同的对象引用。 如果你只有属性而不是方法,并且你不关心具有相同构造函数的完全相同的对象,而只是拥有具有相同值的普通对象,是的,你将拥有一种“深拷贝”。说清楚:function foo(a) this.a = a ; var main = [new foo(1)], temp = JSON.parse(JSON.stringify(main)); 那么你将有main[0].a 等于1temp[0].a 以及。如果您更改最后一个temp[0].a = 4,则更改不会反映到main[0].a。然而main[0].constructorfootemp[0].constructorObject 非常感谢您的回答我感谢您的帮助 template.Temparray(JSON.parse(JSON.stringify(ko.toJS(template.Mainarray()))));我已经使用了上面的 sn-p 并且它与 n=knockout 框架按预期工作。向你致敬 :) 为什么 JavaScript 没有这样的功能呢?就像function cloneObject (o) return JSON.parse(JSON.stringify(o)); ...除了在幕后做一些更快的事情。或者甚至更好:一个用于所有对象的方法 clone() 这样你就可以做到 mainArray.clone() 谢谢@ZER0!使用本机 JSON 函数是我见过的最优雅的建议。【参考方案2】:

Lodash 可用于深度复制对象_.cloneDeep(value)

var objects = [ 'a': 1 ,  'b': 2 ];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// → false

【讨论】:

【参考方案3】:

对于其他有相同问题的人。你也可以这样做。 使用新的es6 features,您可以创建一个数组的副本(没有引用)和一个没有一级引用的每个对象的副本。

const copy = array.map(object => ( ...object ))

恕我直言,它更具功能性和惯用语

注意:传播语法在复制数组时有效地深入一级。因此,它可能不适合复制多维数组,如下例所示(与 Object.assign() 和展开语法相同)。 更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

所以基本上如果您的对象没有对象作为属性。这种语法就是你需要的一切。不幸的是,规范中没有“开箱即用”的深度克隆功能,但如果需要,您可以随时使用库

浏览器兼容性警告:我认为它现在是 Ecma 规范的一部分,但有些浏览器没有完整的 support 扩展语法喷射。但是使用其中一种流行的转译器就可以了

【讨论】:

【参考方案4】:

要复制数组的值而不复制数组的引用,您可以这样做:

const tempArray = [...mainArray];

这是 AirBnb 的 JS 样式指南推荐的解决方案:https://github.com/airbnb/javascript#arrays

但是,这不会为数组中的对象创建新的引用。要为数组和里面的对象创建一个新的引用,你可以这样做:

JSON.parse(JSON.stringify(mainArray));

【讨论】:

数组没有引用,但里面的对象是。 对于数组数组,试试这个:var start = [[4,2,6,5],[1,8,7,3]]; var temp = start.map(e => e.slice(0)); var tempEs6 = start.map(e => [...e]);【参考方案5】:

所以你想要一个没有对象引用的深拷贝?当然,使用.slice()

例子:

var mainArr = [],
    tmpArr = []

tmpArr = mainArr.slice(0) // Shallow copy, no reference used.

PS:我不认为双 JSON 解析是 performance wise。

【讨论】:

这在 Google Chrome 25 下对我不起作用。在我修改了新数组的第一个对象后,它也修改了原始数组的第一个对象。虽然没有反对意见,因为它确实适用于简单的数组,只是不适用于我认为是 OP 的点的对象数组。 这对我也不起作用。 ***.com/questions/28482593/… 但是双 JSON 解析工作...根据 MDN (developer.mozilla.org/en/docs/Web/JavaScript/Reference/…):“对于对象引用(而不是实际对象),切片将对象引用复制到新数组中。两者都是原始的和新数组引用同一个对象。如果引用的对象发生更改,则更改对新数组和原始数组都是可见的。" 如果数组中有对象,这将不起作用。它将复制对象引用。 正如大家所说。除非您在数组中有简单的对象,否则这根本不起作用。在大多数情况下使用大多数 Js 框架时,这将不起作用(这是过于简单化了)。这个答案没有回答问题。【参考方案6】:

你可以使用Angular's copy:angular.copy();

【讨论】:

【参考方案7】:

在嵌套数组上你可以这样做:

    const origin = [ cat: 'Bengal', dog: 'Birman' ,  cat: 'Abyssinian', dog: 'Bombay' ];
    const clone = [];
    origin.forEach(v=> clone.push(Object.assign(, v)));

【讨论】:

【参考方案8】:

使用angular.copy。但不适用于整个数组(因为它会通过引用传递数组项),而是迭代它并在其成员上使用angular.copy

var newArray = [];
for (var i = 0, item; item = mainArray[i];) 
    newArray[i] = angular.copy(item);
    i++;

【讨论】:

以上是关于在javascript中将对象数组复制到另一个数组而没有对象引用(深拷贝)的主要内容,如果未能解决你的问题,请参考以下文章

在JavaScript中将一个数组附加到另​​一个数组[重复]

如何在 C# 中将数组的一部分复制到另一个数组?

在C中将奇数索引元素从一个数组复制到另一个数组

如何在javascript中将一个数组中的值添加到另一个数组

React中将对象从数组移动到数组到另一个对象时的位置镜像

如何在 TypeScript Angular 2 中将 Json 对象数组映射到另一个普通 json 对象