对象克隆
当你想要一个对象的完整副本(即对象属性和这些属性中的值等等)时,称为深度克隆。
Version >= 5.1
如果一个对象可以序列化为 JSON,那么你可以使用 JSON.parse
和 JSON.stringify
的组合创建它的深度克隆:
var existing = { a: 1, b: { c: 2 } };
var copy = JSON.parse(JSON.stringify(existing));
existing.b.c = 3; // copy.b.c will not change
请注意,JSON.stringify
会将 Date
对象转换为 ISO 格式的字符串表示形式,但 JSON.parse
不会将字符串转换回 Date
。
JavaScript 中没有用于创建深度克隆的内置函数,并且通常不可能出于多种原因为每个对象创建深度克隆。例如,
- 对象可以具有无法检测到的不可枚举和隐藏属性。
- 对象 getter 和 setter 无法复制。
- 对象可以具有循环结构。
- 函数属性可以取决于隐藏范围中的状态。
假设你有一个 nice
对象,其属性仅包含原始值,日期,数组或其他 nice
对象,则可以使用以下函数来创建深度克隆。它是一个递归函数,可以检测具有循环结构的对象,并在这种情况下抛出错误。
function deepClone(obj) {
function clone(obj, traversedObjects) {
var copy;
// primitive types
if(obj === null || typeof obj !== "object") {
return obj;
}
// detect cycles
for(var i = 0; i < traversedObjects.length; i++) {
if(traversedObjects[i] === obj) {
throw new Error("Cannot clone circular object.");
}
}
// dates
if(obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// arrays
if(obj instanceof Array) {
copy = [];
for(var i = 0; i < obj.length; i++) {
copy.push(clone(obj[i], traversedObjects.concat(obj)));
}
return copy;
}
// simple objects
if(obj instanceof Object) {
copy = {};
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
copy[key] = clone(obj[key], traversedObjects.concat(obj));
}
}
return copy;
}
throw new Error("Not a cloneable object.");
}
return clone(obj, []);
}