1. 程式人生 > 其它 >理解並手寫深拷貝函式

理解並手寫深拷貝函式

let obj1 = {    
  name: 'dog',
  array: [1, 2, 3],
  son: {
    name: 'dogSon'
  }
}
obj2 = obj1;
obj2.name = 'cat';
obj2.son.name = 'catSon';
console.log(obj1.name);     //cat
console.log(obj1.son.name);  //catSon
console.log(obj2.name);     //cat
console.log(obj2.son.name);  //catSon

相信大家都明白,因為物件的淺拷貝,修改obj2屬性後,兩個物件的值同時都被修改了。

不理解的小夥伴可以看下我之前寫的 '從資料型別上理解深淺拷貝'。

除了呼叫已有方法,我們該如何手寫自己的深拷貝呢?

我們的函式方法起名為cloneDeep,而拷貝肯定返回了一個新的物件newObj。

function cloneDeep(obj){
  return newObj;      
}

首先要判定拷貝是否是一個物件,如果不是還看它幹嘛!直接return結束!

function cloneDeep(obj) {
   // 判斷要拷貝的是否為物件  
  if (!obj instanceof Object) {
    return;
  }
  return newObj;
}

對要拷貝的物件進行判斷,對返回的newObj設定資料型別。

function cloneDeep(obj) {
  if (!obj instanceof Object) {
    return;
  }
  // 判斷這個物件是否為陣列
  let newObj = obj instanceof Array ? [] : {};
  return newObj;
}

把物件進行遍歷,然後開始進行拷貝。

function cloneDeep(obj) {
  if (!obj instanceof Object) {
    return;
  }
  let newObj = obj instanceof
Array ? [] : {};   // 通過for...in遍歷物件   for (let key in obj) {     newObj[key] = obj[key];   }   return newObj; }

如果此時執行程式碼進行驗證,我們會發現,目前完成的僅僅是第一層物件的拷貝。

console.log(obj1.name);     //dog
console.log(obj1.son.name);  //catSon
console.log(obj2.name);     //cat
console.log(obj2.son.name);  //catSon

因此可以先判斷拷貝的屬性是否還是一個物件,進行深層次的遞迴。

function cloneDeep(obj) {
  if (!obj instanceof Object) {
    return;
  }
  let newObj = obj instanceof Array ? [] : {};
  for (let key in obj) {
    // 如果物件的屬性還是物件,就進行遞迴處理
    newObj[key] = obj[key] instanceof Object ? cloneDeep(obj[key]) : obj[key];
  }
  return newObj;
}

這樣我們的深拷貝就基本功能就完成了,不過缺點就是for in連帶物件原型上的屬性一起遍歷了。

function cloneDeep(obj) {
  if (!obj instanceof Object) {
    return;
  }
  let newObj = obj instanceof Array ? [] : {};
  for (let key in obj) {
    // 使用 .hasOwnProperty()判斷一個物件是否包含自定義屬性而不是原型鏈上的屬性
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key] instanceof Object ? cloneDeep(obj[key]) : obj[key];
    }
  }
  return newObj;
}

最後來驗證是否達到深拷貝的功能要求。

function cloneDeep(obj) {
  if (!obj instanceof Object) {
    return;
  }
  let newObj = obj instanceof Array ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key] instanceof Object ? cloneDeep(obj[key]) : obj[key];
    }
  }
  return newObj;
}
let obj1 = {    
  name: 'dog',
  array: [1, 2, 3],
  son: {
    name: 'dogSon'
  }
}
obj2 = obj1;
obj2.name = 'cat';
obj2.son.name = 'catSon';
console.log(obj1.name);     //dog
console.log(obj1.son.name);  //dogSon
console.log(obj2.name);     //cat
console.log(obj2.son.name);  //catSon