鲁斯前端布鲁斯前端

文章中英模式

布鲁斯前端JS面试题目 - 实现深拷贝函数

学习如何实现 JavaScript 深拷贝函数,处理复杂的嵌套对象与循环引用,掌握不同深拷贝方案的优缺点与实际应用。

影片縮圖

懒得看文章?那就来看视频吧

浅拷贝与深拷贝的区别

在 JavaScript 中,对象是引用类型,当我们将一个对象赋值给另一个变量时,实际上只是复制了对该对象的引用,而不是对象本身。这就是为什么我们需要了解浅拷贝与深拷贝的区别。

浅拷贝 (Shallow Copy)

浅拷贝只复制对象的第一层属性,对于嵌套的对象或数组,仍然是复制其引用。

// 淺拷貝示例
const original = { a: 1, b: { c: 2 } };

// 使用 Object.assign 進行淺拷貝
const shallowCopy = Object.assign({}, original);

// 使用展開運算符進行淺拷貝
const spreadCopy = { ...original };

// 修改淺拷貝的嵌套屬性
shallowCopy.b.c = 3;

console.log(original.b.c); // 輸出: 3 (原物件也被修改了!)
console.log(spreadCopy.b.c); // 輸出: 3 (同樣被修改了!)

深拷贝 (Deep Copy)

深拷贝会递归地复制所有属性,创建一个与原对象完全独立的新对象,修改新对象不会影响原对象。

基本的深拷贝实现

下面是一个简单的深拷贝函数实现,能够处理基本的嵌套对象和数组:

function deepClone(obj) {
  // 處理基本類型和 null
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  
  // 創建新的物件或陣列
  const copy = Array.isArray(obj) ? [] : {};
  
  // 遞迴複製所有屬性
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      copy[key] = deepClone(obj[key]);
    }
  }
  
  return copy;
}

// 使用範例
const original = {
  a: 1,
  b: {
    c: 2,
    d: [3, 4, { e: 5 }]
  }
};

const cloned = deepClone(original);

// 修改克隆對象的嵌套屬性
cloned.b.c = 10;
cloned.b.d[2].e = 20;

console.log(original.b.c); // 輸出: 2 (原始值保持不變)
console.log(original.b.d[2].e); // 輸出: 5 (原始值保持不變)
console.log(cloned.b.c); // 輸出: 10
console.log(cloned.b.d[2].e); // 輸出: 20

这个基本实现能处理普通对象和数组,但有几个限制:

  • 1. 不能处理循环引用(会导致堆栈溢出)
  • 2. 不能正确处理 Date、RegExp、Map、Set 等特殊对象
  • 3. 不处理对象的原型链
  • 4. 不处理不可枚举属性