【前端面試】深淺拷貝的方法、手寫深拷貝函數

本文內容:
1、三種方法實現對象的淺拷貝
2、兩種方法實現對象的深拷貝
3、實現簡單的深拷貝函數

淺拷貝

方法1:Object.assign()

數組

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = Object.assign(arr);

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 100, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

對象

let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = Object.assign(obj);

newObj.c.m = 100;

console.log(obj);
console.log(newObj);

// { a: 1, b: 2, c: { m: 100, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

方法2:擴展運算符

數組

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = [...arr];

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 100, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

對象

let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = { ...obj };

newObj.c.m = 100;

console.log(obj);
console.log(newObj);

// { a: 1, b: 2, c: { m: 100, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

方法3:遍歷

數組

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = [];
arr.forEach((item) => {
  newArr.push(item);
})

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 100, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

對象

let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = {};
for(let key in obj){
  newObj[key] = obj[key];
}

newObj.c.m = 100;

console.log(obj);
console.log(newObj);

// { a: 1, b: 2, c: { m: 100, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

深拷貝

方法1:lodash插件中 cloneDeep()

const _ = require("lodash");

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = _.cloneDeep(arr);

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 10, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

方法2:JSON.parse() + JSON.stringify()

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = JSON.parse(JSON.stringify(arr));

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 10, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

侷限
會忽略 undefined
會忽略 symbol
不能序列化函數
不能解決循環引用的對象


手寫簡單的深拷貝函數

function deepClone(obj) {
  function isObject(para) {
    return (typeof para === "object" || typeof para === "function") && para !== null;
  }

  if (!isObject(obj)) {
    return obj;
  }
  let cloneObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
    }
  }
  return cloneObj;
}


let arr = [1, 2, 3, [10, 20, 30]];
let newArr = deepClone(arr);
newArr[3][0] = 100;
console.log(arr);
console.log(newArr);
// [ 1, 2, 3, [ 10, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]


let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = deepClone(obj);
newObj.c.m = 100;
console.log(obj);
console.log(newObj);
// { a: 1, b: 2, c: { m: 10, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

思路

  1. 判斷傳入的參數是否爲引用數據類型,若是簡單數據類型則直接返回傳入的參數;
  2. 判斷傳入的參數是數組還是對象,分別初始化對應的結構;
  3. 使用 for in 遍歷對象,判斷該屬性是否爲對象的自有屬性obj.hasOwnProperty(key)
  4. 判斷對應的屬性值是否爲引用數據類型,若是引用數據類型,則需要遞歸調用該函數,若不是則直接添加到初始化的結構上。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章