如何在JavaScript中进行深入克隆
你如何深入克隆一个Javascript对象?
我知道有基于框架的各种功能,如JSON.parse(JSON.stringify(o))
和$.extend(true, {}, o)
但我不想使用这样的框架。
创建深度克隆的最优雅或有效的方式是什么?
我们确实关心像克隆数组这样的边缘情况。 不打破原型链,处理自我参照。
我们不关心支持DOM对象的复制等,因为.cloneNode
存在。
由于我主要想在node.js
使用深度克隆,因此使用V5引擎的ES5功能是可以接受的。
[编辑]
在任何人提出建议之前,让我先提一下,通过从对象原型继承并克隆它来创建副本之间存在明显的区别。 前者弄乱了原型链。
[进一步编辑]
在阅读你的答案后,我发现了一个令人讨厌的发现,即克隆整个物体是一个非常危险和困难的游戏。 以下面的基于闭包的对象为例
var o = (function() {
var magic = 42;
var magicContainer = function() {
this.get = function() { return magic; };
this.set = function(i) { magic = i; };
}
return new magicContainer;
}());
var n = clone(o); // how to implement clone to support closures
有没有办法编写克隆对象的克隆函数,在克隆时具有相同的状态,但不能在JS中编写JS解析器的情况下改变o
的状态。
现在不再需要这种功能了。 这仅仅是学术兴趣。
这真的取决于你想克隆什么。 这是一个真正的JSON对象还是JavaScript中的任何对象? 如果你想做任何克隆,它可能会让你陷入麻烦。 哪个麻烦? 我将在下面解释它,但首先是克隆对象文字,任何原语,数组和节点的代码示例。
function clone(item) {
if (!item) { return item; } // null, undefined values check
var types = [ Number, String, Boolean ],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function(type) {
if (item instanceof type) {
result = type( item );
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
var result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (var i in item) {
result[i] = clone( item[i] );
}
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
if (false && item.constructor) {
// would not advice to do that, reason? Read below
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
}
var copy = clone({
one : {
'one-one' : new String("hello"),
'one-two' : [
"one", "two", true, "four"
]
},
two : document.createElement("div"),
three : [
{
name : "three-one",
number : new Number("100"),
obj : new function() {
this.name = "Object test";
}
}
]
})
现在,我们来讨论克隆REAL对象时可能遇到的问题。 我现在正在谈论,关于你通过做类似的东西创建的对象
var User = function(){}
var newuser = new User();
当然,你可以克隆它们,这不是问题,每个对象都暴露了构造函数属性,并且你可以使用它来克隆对象,但它不会总是有效。 你也可以在这个对象上做简单for in
事情,但它会走向相同的方向 - 麻烦。 我还在代码中包含了克隆功能,但它被if( false )
语句排除。
那么,为什么克隆会是一种痛苦呢? 那么,首先,每个对象/实例都可能有一些状态。 你永远不能确定你的对象没有例如私有变量,如果是这种情况,通过克隆对象,你只是打破了状态。
想象一下,没有国家,没关系。 那么我们还有另一个问题。 通过“构造函数”方法克隆会给我们另一个障碍。 这是一个参数依赖。 你永远无法确定,创造这个东西的人没有做过某种事
new User({
bike : someBikeInstance
});
如果是这种情况,那么你运气不好,有些BikeInstance可能是在某种情况下创建的,而且这种情况对克隆方法来说是未知的。
那么该怎么办? 您仍然可以for in
解决方案中做到这一点,并将这些对象视为普通的对象文字,但是也许这不是克隆这些对象的想法,只是传递此对象的引用?
另一个解决方案是 - 您可以设置一个约定,即所有必须克隆的对象都应该自己实现这个部分并提供适当的API方法(如cloneObject)。 cloneNode
正在为DOM做些什么。
你决定。
非常简单的方式,可能太简单了:
var cloned = JSON.parse(JSON.stringify(objectToClone));
因为JSON不支持undefined
和function () {}
值,所以JSON.parse(JSON.stringify())
组合深入复制Javascript对象是无效的,因此JSON.stringify
将忽略这些代码段将JavaScript对象“串化”(编组)成JSON。
以下函数将深度复制对象,并且不需要第三方库(jQuery,LoDash等)。
function copy(aObject) {
if (!aObject) {
return aObject;
}
var bObject, v, k;
bObject = Array.isArray(aObject) ? [] : {};
for (k in aObject) {
v = aObject[k];
bObject[k] = (typeof v === "object") ? copy(v) : v;
}
return bObject;
}
链接地址: http://www.djcxy.com/p/40741.html
上一篇: How to Deep clone in javascript
下一篇: How to write Event Handlers and detect certain JavaScript calls using HTMLUnit?