这真的取决于你想克隆什么。这是一个真正的 JSON 对象还是 JavaScript 中的任何对象?如果你想做任何克隆,它可能会给你带来一些麻烦。哪个麻烦?我将在下面解释它,但首先是一个克隆对象文字、任何基元、数组和 DOM 节点的代码示例。
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") {
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
});
如果是这种情况,那么您就不走运了, someBikeInstance 可能是在某个上下文中创建的,而该上下文对于 clone 方法来说是未知的。
那么该怎么办?您仍然可以for in
解决问题,并将此类对象视为普通对象文字,但也许根本不克隆此类对象是一个想法,而只是传递此对象的引用?
另一个解决方案是 - 您可以设置一个约定,所有必须克隆的对象都应该自己实现这部分并提供适当的 API 方法(如 cloneObject )。cloneNode
DOM 正在做什么。
你决定。