物件克隆
當你想要一個物件的完整副本(即物件屬性和這些屬性中的值等等)時,稱為深度克隆。
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, []);
}