展開運算子...和Object.assign都是淺拷貝,常見的js方法如slice也是淺拷貝,那如何實現深拷貝呢?
// 需要遞迴拷貝
function deepClone(obj) {
// 如果傳遞的是null 那就不處理
// 函式沒有引用關係
if (typeof obj !== 'object') return obj;
if (obj == null) return null;
// 處理日期和正則
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
// Object.prototype.toString.call(obj) === '[object Array]', 這麼判斷保留不了繼承關係
let instance = new obj.constructor(); // 看當前例項的constructor
// 實現深拷貝
//for...in迴圈是 遍歷物件的每一個可列舉屬性,包括原型鏈上面的可列舉屬性,
for (let key in obj) {
if(obj.hasOwnProperty(obj[key])) {
instance[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
}
}
return instance;
}
// 函式不需要重新拷貝
let obj = { a: { a: 1 } }
let newObj = deepClone(obj);
obj.a.a = 2;
console.log(newObj);
複製程式碼
思路是首先判斷obj型別,null、Date物件,陣列、正則、以及物件的typeof結果都是oobject, 需要單獨分情況考慮。 對於null、Date物件以及正則,我們直接返回數值就可以了 對於陣列,我們沒有直接返回,因為陣列可能有繼承關係,需要保留繼承關係,這個需要注意。 1)判斷陣列型別我們沒用Object.prototype.toString.call(obj),因為它保留不了繼承關係。 舉例如下:
var t = [1,2]
t.__proto__={a:1}
Object.prototype.toString.call(t) ----> // "[object Array]"
t.constructor -----> // ƒ Object() { [native code] }
new t.constructor() --> objcet
複製程式碼
補充一下instanceof f instanceof Foo判斷邏輯是: f的__proto__一層一層往上,能否對應到Foo.prototype