文章中英模式
布鲁斯前端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. 不处理不可枚举属性