js實現深拷貝

蘆夢宇發表於2018-05-26

展開運算子...和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

相關文章