您如何在Javascript中克隆对象数组?

...每个对象还引用了同一数组中的其他对象吗?

当我第一次想到这个问题时

var clonedNodesArray = nodesArray.clone()

将存在并搜索有关如何在javascript中克隆对象的信息。我确实在StackOverflow上发现了一个问题(由相同的@JohnResig回答),他指出,使用jQuery,您可以做到

var clonedNodesArray = jQuery.extend({}, nodesArray);

克隆对象。我尝试了一下,但这只复制了数组中对象的引用。所以如果我

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

nodeArray [0]和clonedNodesArray [0]的值都将变为“绿色”。然后我尝试

var clonedNodesArray = jQuery.extend(true, {}, nodesArray);

它深深复制了一个对象,但是我分别从Firebug和Opera Dragonfly 得到了“ 太多的递归 ”和“ 控制堆栈溢出 ”消息。

你会怎么做?这是什至不应该做的事情吗?有没有一种可重用的方式来做到这一点在Javascript中?

ProJinJin2020/03/17 11:53:56

If you want to implement deep clone use JSON.parse(JSON.stringify(your {} or []))

const myObj ={
    a:1,
    b:2,
    b:3
}

const deepClone=JSON.parse(JSON.stringify(myObj));
deepClone.a =12;
console.log("deepClone-----"+myObj.a);
const withOutDeepClone=myObj;
withOutDeepClone.a =12;
console.log("withOutDeepClone----"+myObj.a);

乐卡卡西卡卡西2020/03/17 11:53:56

Depending if you have Underscore or Babel here is a Benchmark of the different way of deep cloning an array.

https://jsperf.com/object-rest-spread-vs-clone/2

Look like babel is the fastest.

var x = babel({}, obj)
Pro小宇宙2020/03/17 11:53:56

with jQuery:

var target= [];
$.each(source, function() {target.push( $.extend({},this));});
2020/03/17 11:53:56

Some elegant ways for deep cloning in javascript

https://mootools.net/core/docs/1.6.0/Types/Object

https://scotch.io/bar-talk/copying-objects-in-javascript

1) A vanilla Javascript method for cloning objects

2) A clever exploit of the JSON library to deep-clone objects

3) Using jQuery’s $.extend() function

4) Using Mootools’ clone() function to clone objects

Stafan猿2020/03/17 11:53:56

I use the new ECMAScript 6 Object.assign method :

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

the first argument of this method is the array to be update, we pass an empty object because we want to have a new object.

we can also use this syntax, which is the same but shorter :

let newObject = [...oldObject];
Harry2020/03/17 11:53:56

In JavaScript, array and object copy change the origin values, so Deep copy is the solution for this.

A deep copy means actually creating a new array and copying over the values, since whatever happens to it will never affect the origin one.

JSON.parse and JSON.stringify is the best and simple way to Deep copy. The JSON.stringify() method converts a JavaScript value to a JSON string.The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string.

//Deep Clone

let a = [{ x:{z:1} , y: 2}];
let b = JSON.parse(JSON.stringify(a));
b[0].x.z=0

console.log(JSON.stringify(a)); //[{"x":{"z":1},"y":2}]
console.log(JSON.stringify(b)); // [{"x":{"z":0},"y":2}]

For more details: Read Here

小宇宙Green2020/03/17 11:53:56

I was pretty frustrated by this problem. Apparently the problem arises when you send in a generic Array to the $.extend method. So, to fix it, I added a little check, and it works perfectly with generic arrays, jQuery arrays, and any objects.

jQuery.extend({
    deepclone: function(objThing) {
        // return jQuery.extend(true, {}, objThing);
        /// Fix for arrays, without this, arrays passed in are returned as OBJECTS! WTF?!?!
        if ( jQuery.isArray(objThing) ) {
            return jQuery.makeArray( jQuery.deepclone($(objThing)) );
        }
        return jQuery.extend(true, {}, objThing);
    },
});

Invoke using:

var arrNewArrayClone = jQuery.deepclone(arrOriginalArray);
// Or more simply/commonly
var arrNewArrayClone = $.deepclone(arrOriginalArray);
伽罗小哥2020/03/17 11:53:56

Array.slice can be used to copy an array or part of an array.. http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html This would work with strings and numbers .. - changing a string in one array would not affect the other - but objects are still just copied by reference so changes to referenced objects in one array would have an affect on the other array.

Here is an example of a JavaScript undo manager that could be useful for this :http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx

逆天村村2020/03/17 11:53:56

My approach:

var temp = { arr : originalArray };
var obj = $.extend(true, {}, temp);
return obj.arr;

gives me a nice, clean, deep clone of the original array - with none of the objects referenced back to the original :-)

启人Green2020/03/17 11:53:56

JQuery extend is working fine, just you need to specify that you are cloning an array rather than an object (note the [] instead of {} as parameter to the extend method):

var clonedNodesArray = jQuery.extend([], nodesArray);
达蒙小小2020/03/17 11:53:56

Map将从旧的数组创建新数组(不引用旧的数组),然后在地图内部创建新对象并遍历属性(键),并将旧Array对象中的值分配给新对象的coresponding属性。

这将创建完全相同的对象数组。

let newArray = oldArray.map(a => {
               let newObject = {};
               Object.keys(a).forEach(propertyKey => {
                    newObject[propertyKey] = a[propertyKey];
               });
               return newObject ;
});
小胖番长2020/03/17 11:53:56
$.evalJSON($.toJSON(origArray));
Eva伽罗2020/03/17 11:53:56

这对我有用:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend({}, obj);
                  });

如果您需要数组中对象的深层副本,请执行以下操作:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend(true, {}, obj);
                  });
阿飞小胖2020/03/17 11:53:56

我用Object.assign解决了对象数组的克隆问题

const newArray = myArray.map(a => Object.assign({}, a));

甚至更短的传播语法

const newArray = myArray.map(a => ({...a}));
Davaid神无2020/03/17 11:53:56

如果您需要的只是浅表副本,那么一个真正简单的方法是:

new_array = old_array.slice(0);
Tony伽罗2020/03/17 11:53:55

进行此克隆的最佳方法和最新方法如​​下:

使用...ES6传播算子。

这是最简单的示例:

var clonedObjArray = [...oldObjArray];

这样,我们将数组分散为各个值,然后使用[]运算符将其放入新数组中。

这是一个更长的示例,显示了其不同的工作方式:

let objArray = [ {a:1} , {b:2} ];

let refArray = objArray; // this will just point to the objArray
let clonedArray = [...objArray]; // will clone the array

console.log( "before:" );
console.log( "obj array" , objArray );
console.log( "ref array" , refArray );
console.log( "cloned array" , clonedArray );

objArray[0] = {c:3};

console.log( "after:" );
console.log( "obj array" , objArray ); // [ {c:3} , {b:2} ]
console.log( "ref array" , refArray ); // [ {c:3} , {b:2} ]
console.log( "cloned array" , clonedArray ); // [ {a:1} , {b:2} ]

Harry古一2020/03/17 11:53:55

只要您的对象包含JSON可序列化的内容(没有函数,no Number.POSITIVE_INFINITY等),就不需要任何循环来克隆数组或对象。这是纯香草的单线解决方案。

var clonedArray = JSON.parse(JSON.stringify(nodesArray))

总结下面的评论,这种方法的主要优点是它还可以克隆数组的内容,而不仅仅是数组本身。主要缺点是只能处理JSON可序列化内容的局限性以及它的性能(这比slice基于方法的性能差很多)。

梅前端斯丁2020/03/17 11:53:55

浅表副本的问题是未克隆所有对象。尽管每个对象的引用在每个数组中都是唯一的,但是一旦最终抓住它,您将像以前一样处理同一对象。克隆它的方式没有错...使用Array.slice()会产生相同的结果。

您的深层副本有问题的原因是因为您最终得到了循环对象引用。Deep将尽可能深入,如果您有一个圆圈,它将无限循环直到浏览器晕倒为止。

如果数据结构不能表示为有向无环图,那么我不确定您是否能够找到用于深度克隆的通用方法。循环图提供了许多棘手的极端情况,由于这不是常见的操作,我怀疑有人编写了完整的解决方案(如果可能的话-可能不是!但是我现在没有时间尝试编写严格的证明。)。此页面上,我对此问题发表了一些很好的评论

如果您需要带有循环引用的对象数组的深层副本,我相信您将必须编写自己的方法来处理您的专用数据结构,例如多遍克隆:

  1. 在第一轮中,克隆所有不引用数组中其他对象的对象。跟踪每个对象的起源。
  2. 在第二轮中,将对象链接在一起。