展開運(yùn)算符...和Object.assign都是淺拷貝,常見的js方法如slice也是淺拷貝,那如何實(shí)現(xiàn)深拷貝呢?
// 需要遞歸拷貝
function deepClone(obj) {
// 如果傳遞的是null 那就不處理
// 函數(shù)沒有引用關(guān)系
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]', 這么判斷保留不了繼承關(guān)系
let instance = new obj.constructor(); // 看當(dāng)前實(shí)例的constructor
// 實(shí)現(xiàn)深拷貝
//for...in循環(huán)是 遍歷對(duì)象的每一個(gè)可枚舉屬性,包括原型鏈上面的可枚舉屬性,
for (let key in obj) {
if(obj.hasOwnProperty(obj[key])) {
instance[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
}
}
return instance;
}
// 函數(shù)不需要重新拷貝
let obj = { a: { a: 1 } }
let newObj = deepClone(obj);
obj.a.a = 2;
console.log(newObj);
復(fù)制代碼思路是首先判斷obj類型,null、Date對(duì)象,數(shù)組、正則、以及對(duì)象的typeof結(jié)果都是oobject,
需要單獨(dú)分情況考慮。
對(duì)于null、Date對(duì)象以及正則,我們直接返回?cái)?shù)值就可以了
對(duì)于數(shù)組,我們沒有直接返回,因?yàn)閿?shù)組可能有繼承關(guān)系,需要保留繼承關(guān)系,這個(gè)需要注意。
1)判斷數(shù)組類型我們沒用Object.prototype.toString.call(obj),因?yàn)樗A舨涣死^承關(guān)系。
舉例如下:
var t = [1,2]
t.__proto__={a:1}
Object.prototype.toString.call(t) ----> // "[object Array]"
t.constructor -----> // ? Object() { [native code] }
new t.constructor() --> objcet
總結(jié)
實(shí)現(xiàn)深拷貝的幾個(gè)要點(diǎn):
- 需要遞歸拷貝。
- 需要判斷類型
- 無(wú)法拷貝proto