...其中每个对象还引用同一数组中的其他对象?
当我第一次提出这个问题时,我只是喜欢
var clonedNodesArray = nodesArray.clone()
将存在并搜索有关如何在javascript中克隆对象的信息。我确实在StackOverflow上找到了question(由同样的@JohnResig回答)他指出用jQuery你可以做到
var clonedNodesArray = jQuery.extend({}, nodesArray);
克隆一个对象。我试过这个,但这只复制了数组中对象的引用。所以,如果我
nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"
nodesArray [0]和clonedNodesArray [0]的值都将变为“绿色”。然后我试了
var clonedNodesArray = jQuery.extend(true, {}, nodesArray);
深度复制了一个Object,但我分别从Firebug和Opera Dragonfly那里得到了“太多的递归”和“控制堆栈溢出”消息。
你会怎么做?这是不应该做的事吗?在Javascript中是否有可重用的方法?
答案 0 :(得分:470)
只要您的对象包含JSON可序列化的内容(没有函数,没有Number.POSITIVE_INFINITY
等),就不需要任何循环来克隆数组或对象。这是一个纯粹的香草单行解决方案。
var clonedArray = JSON.parse(JSON.stringify(nodesArray))
总结下面的评论,这种方法的主要优点是它还克隆了数组的内容,而不仅仅是数组本身。主要缺点是它仅限于处理JSON可序列化内容,以及它的性能(这比基于slice
的方法要差得多。)
答案 1 :(得分:220)
我解决了使用Object.assign
克隆一组对象的问题const newArray = myArray.map(a => Object.assign({}, a));
使用spread syntax 或更短
const newArray = myArray.map(a => ({...a}));
答案 2 :(得分:158)
如果您只需要浅色副本,一个非常简单的方法是:
new_array = old_array.slice(0);
答案 3 :(得分:93)
浅拷贝的问题是没有克隆所有对象。虽然每个对象的引用在每个数组中都是唯一的,但是一旦你最终抓住它,你就会像以前一样处理同一个对象。克隆它的方式没有任何问题......使用Array.slice()会产生相同的结果。
您的深层复制存在问题的原因是因为您最终会遇到循环对象引用。 Deep会尽可能深入,如果你有一个圆圈,它会一直无限地继续前进,直到浏览器晕倒。
如果数据结构不能表示为有向非循环图,那么我不确定您是否能够找到一种用于深度克隆的通用方法。循环图提供了许多棘手的极端情况,因为它不是一个常见的操作,我怀疑是否有人编写了完整的解决方案(如果它甚至可能 - 它可能不是!但我现在没有时间尝试编写严格的证据。)。我在this page上找到了一些关于这个问题的好评。
如果你需要带有循环引用的对象数组的深层副本,我相信你将需要编写自己的方法来处理你的专用数据结构,这样它就是一个多遍克隆:
答案 4 :(得分:43)
最佳和最新的克隆方法如下:
使用“......”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} ]
答案 5 :(得分:25)
这对我有用:
var clonedArray = $.map(originalArray, function (obj) {
return $.extend({}, obj);
});
如果您需要数组中对象的深层副本:
var clonedArray = $.map(originalArray, function (obj) {
return $.extend(true, {}, obj);
});
答案 6 :(得分:18)
$.evalJSON($.toJSON(origArray));
答案 7 :(得分:8)
我可能有一个简单的方法来做到这一点,而不必进行痛苦的递归,也不知道所讨论的对象的所有细节。使用jQuery,只需使用jQuery $.toJSON(myObjectArray)
将对象转换为JSON,然后获取JSON字符串并将其评估回对象。 BAM!做完了!问题解决了。 :)
var oldObjArray = [{ Something: 'blah', Cool: true }];
var newObjArray = eval($.toJSON(oldObjArray));
答案 8 :(得分:8)
我正在回答这个问题,因为似乎没有一个简单而明确的解决方案来解决“在Javascript中克隆一个对象数组”的问题:
function deepCopy (arr) {
var out = [];
for (var i = 0, len = arr.length; i < len; i++) {
var item = arr[i];
var obj = {};
for (var k in item) {
obj[k] = item[k];
}
out.push(obj);
}
return out;
}
// test case
var original = [
{'a' : 1},
{'b' : 2}
];
var copy = deepCopy(original);
// change value in copy
copy[0]['a'] = 'not 1';
// original[0]['a'] still equals 1
此解决方案迭代数组值,然后迭代对象键,将后者保存到新对象,然后将该新对象推送到新数组。
见jsfiddle。注意:简单的.slice()
或[].concat()
对于数组中的对象是不够的。
答案 9 :(得分:8)
Map将从旧数组创建新数组(不引用旧数组),并在地图内创建新对象并迭代properties(键)并将旧数组对象中的值赋值给与新对象相对应的属性。
这将创建完全相同的对象数组。
let newArray = oldArray.map(a => {
let newObject = {};
Object.keys(a).forEach(propertyKey => {
newObject[propertyKey] = a[propertyKey];
});
return newObject ;
});
答案 10 :(得分:7)
如果要实现深度克隆,请使用JSON.parse(JSON.stringify(您的{}或[]))
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);
答案 11 :(得分:6)
JQuery扩展工作正常,只需指定您正在克隆数组而不是对象(注意[]而不是{}作为extend方法的参数):
var clonedNodesArray = jQuery.extend([], nodesArray);
答案 12 :(得分:5)
正如Daniel Lew所提到的,循环图有一些问题。如果我遇到这个问题,我会在有问题的对象中添加特殊的clone()
方法,或者记住我已经复制过的对象。
我会使用变量copyCount
来执行此操作,每次复制代码时变量都会增加1。将复制比当前复制过程低copyCount
的对象。如果不是,则应引用已存在的副本。这使得必须从原始链接到其副本。
还有一个问题:记忆。如果从一个对象到另一个对象有这个引用,浏览器可能无法释放这些对象,因为它们总是从某个地方引用。您必须进行第二次传递,将所有复制引用设置为Null。 (如果你这样做,你不必拥有copyCount
,但布尔isCopied
就足够了,因为你可以重置第二遍中的值。)
答案 13 :(得分:5)
为此,lodash具有cloneDeep
功能:
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
答案 14 :(得分:4)
我的方法:
var temp = { arr : originalArray };
var obj = $.extend(true, {}, temp);
return obj.arr;
给了我一个漂亮,干净,深刻的原始数组克隆 - 没有任何对象被引用回原始数据: - )
答案 15 :(得分:4)
Array.slice可用于复制数组或数组的一部分。 http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html 这将适用于字符串和数字.. - 更改一个数组中的字符串不会影响另一个 - 但对象仍然只是通过引用复制,因此对一个数组中引用的对象的更改将对另一个数组产生影响。
以下是一个可能对此有用的JavaScript撤消管理器示例:http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx
答案 16 :(得分:3)
我使用新的ECMAScript 6 Object.assign方法:
let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject);
此方法的第一个参数是要更新的数组, 我们传递一个空对象,因为我们想要一个新对象。
我们也可以使用这种语法,它相同但更短:
let newObject = [...oldObject];
答案 17 :(得分:3)
我对这个问题非常沮丧。显然,当您将通用数组发送到$ .extend方法时会出现问题。所以,要修复它,我添加了一些检查,它与泛型数组,jQuery数组和任何对象完美配合。
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);
},
});
使用以下方式调用:
var arrNewArrayClone = jQuery.deepclone(arrOriginalArray);
// Or more simply/commonly
var arrNewArrayClone = $.deepclone(arrOriginalArray);
答案 18 :(得分:3)
忘记eval()(是JS最误用的功能,使代码变慢)和slice(0)(仅适用于简单数据类型)
对我来说这是最好的解决方案:
Object.prototype.clone = function() {
var myObj = (this instanceof Array) ? [] : {};
for (i in this) {
if (i != 'clone') {
if (this[i] && typeof this[i] == "object") {
myObj[i] = this[i].clone();
} else
myObj[i] = this[i];
}
}
return myObj;
};
答案 19 :(得分:3)
此方法非常简单,您可以在不修改原始数组的情况下修改克隆。
// Original Array
let array = [{name: 'Rafael'}, {name: 'Matheus'}];
// Cloning Array
let clone = array.map(a => {return {...a}})
// Editing the cloned array
clone[1].name = 'Carlos';
console.log('array', array)
// [{name: 'Rafael'}, {name: 'Matheus'}]
console.log('clone', clone)
// [{name: 'Rafael'}, {name: 'Carlos'}]
答案 20 :(得分:2)
这会深度复制数组,对象,null和其他标量值,并且还会深层复制非本机函数的任何属性(这种情况非常罕见但可能)。 (为了提高效率,我们不会尝试在数组上复制非数字属性。)
function deepClone (item) {
if (Array.isArray(item)) {
var newArr = [];
for (var i = item.length; i-- > 0;) {
newArr[i] = deepClone(item[i]);
}
return newArr;
}
if (typeof item === 'function' && !(/\(\) \{ \[native/).test(item.toString())) {
var obj;
eval('obj = '+ item.toString());
for (var k in item) {
obj[k] = deepClone(item[k]);
}
return obj;
}
if (item && typeof item === 'object') {
var obj = {};
for (var k in item) {
obj[k] = deepClone(item[k]);
}
return obj;
}
return item;
}
答案 21 :(得分:2)
我们可以发明一种简单的递归Array方法来克隆多维数组。虽然嵌套数组中的对象保持对源数组中相应对象的引用,但数组不会。
Array.prototype.clone = function(){
return this.map(e => Array.isArray(e) ? e.clone() : e);
};
var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));
答案 22 :(得分:1)
在javascript中进行深度克隆的一些优雅方法
https://mootools.net/core/docs/1.6.0/Types/Object
https://scotch.io/bar-talk/copying-objects-in-javascript
1)用于克隆对象的vanilla Javascript方法
2)巧妙利用JSON库深度克隆对象
3)使用jQuery的$ .extend()函数
4)使用Mootools的clone()函数克隆对象
答案 23 :(得分:1)
以下代码将递归执行deep copying of objects and array:
function deepCopy(obj) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
var out = [], i = 0, len = obj.length;
for ( ; i < len; i++ ) {
out[i] = arguments.callee(obj[i]);
}
return out;
}
if (typeof obj === 'object') {
var out = {}, i;
for ( i in obj ) {
out[i] = arguments.callee(obj[i]);
}
return out;
}
return obj;
}
答案 24 :(得分:1)
使用jQuery:
var target= [];
$.each(source, function() {target.push( $.extend({},this));});
答案 25 :(得分:0)
取决于你是否拥有下划线或者Babel,这是深度克隆阵列的不同方式的基准。
https://jsperf.com/object-rest-spread-vs-clone/2
看起来像巴贝尔是最快的。
var x = babel({}, obj)
答案 26 :(得分:0)
对于克隆对象,我只是建议ECMAScript 6 reduce()
:
const newArray=myArray.reduce((array, element)=>array.push(Object.assign({}, element)), []);
但坦率地说,我更喜欢@dinodsaurus的答案。我只是把这个版本作为另一种选择,但我个人将按照@dinodsaurus的建议使用map()
。
答案 27 :(得分:0)
UserPrincipal
答案 28 :(得分:0)
我认为设法编写一种深度克隆任何JavaScript结构的泛型方法,主要使用Object.create
,这在所有现代浏览器中都是支持的。代码是这样的:
function deepClone (item) {
if (Array.isArray(item)) {
var newArr = [];
for (var i = item.length; i-- !== 0;) {
newArr[i] = deepClone(item[i]);
}
return newArr;
}
else if (typeof item === 'function') {
eval('var temp = '+ item.toString());
return temp;
}
else if (typeof item === 'object')
return Object.create(item);
else
return item;
}
答案 29 :(得分:0)
在JavaScript中,数组和对象副本会更改原始值,因此深度复制是解决此问题的方法。
深层复制实际上意味着创建一个新数组并复制值,因为发生的任何事情都不会影响原始数组。
JSON.parse
和JSON.stringify
是进行深度复制的最佳和简单方法。 JSON.stringify()
方法将JavaScript值转换为JSON字符串。JSON.parse()
方法解析JSON字符串,以构造JavaScript值或该字符串描述的对象。
//深度克隆
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}]
有关更多详细信息:Read Here
答案 30 :(得分:0)
这是我的解决方案,它适用于对象数组或Map。此解决方案还保留了方法。
深层复制实际上意味着创建一个新数组并复制值,因为发生的任何事情都不会影响原始数组。
这是最适合我的解决方案:
deepCopy(inputObj: any) {
var newObj = inputObj;
if (inputObj && typeof inputObj === "object") {
newObj = Object.prototype.toString.call(inputObj) === "[object Array]" ? [] : {};
for (var i in inputObj) {
newObj[i] = this.deepCopy(inputObj[i]);
}
//For maps
if(Object.prototype.toString.call(inputObj) === "[object Map]"){
newObj = new Map;
inputObj.forEach((v,k) =>{
newObj.set(k,this.deepCopy(v));
});
}
}
return newObj;
}
答案 31 :(得分:0)
person1 = {
name: 'Naved',
last: 'Khan',
clothes: {
jens: 5,
shirts: 10
}
};
person2 = {
name: 'Naved',
last: 'Khan'
};
// first way shallow copy single lavel copy
// const person3 = { ...person1 };
// secound way shallow copy single lavel copy
// const person3 = Object.assign({}, person1);
// third way shallow copy single lavel copy but old
// const person3 = {};
// for (let key in person1) {
// person3[key] = person1[key];
// }
// deep copy with array and object best way
const person3 = JSON.parse(JSON.stringify(person1));
person3.clothes.jens = 20;
console.log(person1);
console.log(person2);
console.log(person3);
答案 32 :(得分:0)
我正在使用 VUE,因此数组/对象具有附加的 Vue 功能代码。我尝试了许多给出的答案,但最终使用了 clone-deep。
答案 33 :(得分:-1)
function deepCloneArray(array) {
return Array.from(Object.create(array));
}