javascript - 如何正确克隆JavaScript对象?

100 1

我有一个对象,x ,将它作为对象y复制,这样对y的更改不会修改x

如何正确克隆JavaScript对象?

时间: 原作者:

71 0

一个解决方案可能是调用对象属性的源constructor来获取初始复制对象,然后复制属性,例如,Date对象将它数据存储为隐藏成员:


function clone(obj) {


 if (null == obj ||"object" != typeof obj) return obj;


 var copy = obj.constructor();


 for (var attr in obj) {


 if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];


 }


 return copy;


}



var d1 = new Date();



/* Executes function after 5 seconds. */


setTimeout(function(){


 var d2 = clone(d1);


 alert("d1 =" + d1.toString() +"nd2 =" + d2.toString());


}, 5000);



使一个Date与另一个相同的方法是调用setTime方法,但是,这是特定于Date类的。

当我必须实现深度复制时,假设我只需复制一个纯Object,Array,Date,String,Number或Boolean ,最后三种类型是不可变的,所以,我可以执行一个简单的复制,而不必担心它的变化,我进一步假定ObjectArray中包含的元素也将是该列表中6个简单类型之一,这可以通过如下代码完成:


function clone(obj) {


 var copy;



 // Handle the 3 simple types, and null or undefined


 if (null == obj ||"object" != typeof obj) return obj;



 // Handle Date


 if (obj instanceof Date) {


 copy = new Date();


 copy.setTime(obj.getTime());


 return copy;


 }



 // Handle Array


 if (obj instanceof Array) {


 copy = [];


 for (var i = 0, len = obj.length; i < len; i++) {


 copy[i] = clone(obj[i]);


 }


 return copy;


 }



 // Handle Object


 if (obj instanceof Object) {


 copy = {};


 for (var attr in obj) {


 if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);


 }


 return copy;


 }



 throw new Error("Unable to copy obj! Its type isn't supported.");


}



只要对象和数组中的数据形成一个树结构,上面的函数就可以适用于我提到的6个简单类型,也就是说,对象中不存在对同一数据的多个引用,例如:


// This would be cloneable:


var tree = {


"left" : {"left" : null,"right" : null,"data" : 3 },


"right" : null,


"data" : 8


};



// This would kind-of work, but you would get 2 copies of the 


// inner node instead of 2 references to the same copy


var directedAcylicGraph = {


"left" : {"left" : null,"right" : null,"data" : 3 },


"data" : 8


};


directedAcyclicGraph["right"] = directedAcyclicGraph["left"];



// Cloning this would cause a stack overflow due to infinite recursion:


var cyclicGraph = {


"left" : {"left" : null,"right" : null,"data" : 3 },


"data" : 8


};


cyclicGraph["right"] = cyclicGraph;



原作者:
107 3

如果在对象中不使用函数,很简单的:


var cloneOfA = JSON.parse(JSON.stringify(a));



对于包含对象,数组,字符串,布尔值和数字的所有对象都适用。

请参见关于浏览器结构化克隆算法的研究,它用于向worker 发送消息和发送消息,它还包含一个用于深度克隆的函数。

原作者:
86 5

使用jQuery,可以使用扩展


var copiedObject = jQuery.extend({}, originalObject)



对copiedObject的后续更改不会影响原始对象,反之亦然。

要执行深层拷贝:


var copiedObject = jQuery.extend(true, {}, originalObject)



原作者:
106 3

在ECMAScript 6中有Object.assign方法,它将所有可枚举属性的值从一个对象复制到另一个对象,例如:


var x = {myProp:"value"};


var y = Object.assign({}, x); 



但是,请注意,嵌套对象仍然作为引用复制。

原作者:
116 1

每次MDN

  • 如果需要浅拷贝请使用Object.assign({}, a)
  • 对于"深"拷贝请使用JSON.parse(JSON.stringify(a))

不需要外部库,但是你需要检查浏览器兼容性

原作者:
116 4
在一行代码中克隆Javascript对象的一种优雅方法

Object.assign方法是ECMAScript 2015 (ES6 )标准的一部分,它完全满足你的需要。


var clone = Object.assign({}, obj);



Object.assign()方法用于从一个或多个源对象将所有可枚举属性的值复制到目标对象。

阅读更多。

支持旧浏览器的polyfill :


if (!Object.assign) {


 Object.defineProperty(Object, 'assign', {


 enumerable: false,


 configurable: true,


 writable: true,


 value: function(target) {


 'use strict';


 if (target === undefined || target === null) {


 throw new TypeError('Cannot convert first argument to object');


 }



 var to = Object(target);


 for (var i = 1; i < arguments.length; i++) {


 var nextSource = arguments[i];


 if (nextSource === undefined || nextSource === null) {


 continue;


 }


 nextSource = Object(nextSource);



 var keysArray = Object.keys(nextSource);


 for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {


 var nextKey = keysArray[nextIndex];


 var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);


 if (desc !== undefined && desc.enumerable) {


 to[nextKey] = nextSource[nextKey];


 }


 }


 }


 return to;


 }


 });


}



原作者:
123 3

如果你要浅拷贝,那么underscore.js库有一个克隆方法。

 
y =_.clone(x);



 

或者你可以像这样扩展


copiedObject = _.extend({},originalObject);



原作者:
68 5

假设下面有这个对象,并且想要克隆它:


let obj = {a:1, b:2, c:3}; //ES6



或者


var obj = {a:1, b:2, c:3}; //ES5



你可以在ES6 中使用ECMAscript,你可以简单地使用Object.assign来执行克隆:


let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};



或者使用类似这样的扩展运算符:


let cloned = {...obj}; //new {a:1, b:2, c:3};



但是如果你使用ES5,你只有很少的方法,但是可以用JSON.stringify,只要确保你没有大量的数据复制,但是,在许多情况下它可能是一种方便的方式,如下所示:


let cloned = JSON.parse(JSON.stringify(obj)); 


//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over



原作者:
...