深拷贝与浅拷贝
JavaScript 中深拷贝与浅拷贝的区别及实现方式
问题
深拷贝与浅拷贝的区别是什么?如何实现深拷贝?
解答
浅拷贝
浅拷贝只复制对象的第一层属性,嵌套对象仍然是引用关系。
// 浅拷贝方法
const obj = { a: 1, b: { c: 2 } };
// 方法1: Object.assign
const copy1 = Object.assign({}, obj);
// 方法2: 展开运算符
const copy2 = { ...obj };
// 验证:修改嵌套对象会影响原对象
copy1.b.c = 100;
console.log(obj.b.c); // 100 - 原对象被修改了
深拷贝
深拷贝会递归复制所有层级,新对象与原对象完全独立。
// 方法1: JSON 序列化(简单但有局限)
const deepCopy1 = JSON.parse(JSON.stringify(obj));
// 方法2: 手写递归实现
function deepClone(obj, map = new WeakMap()) {
// 处理基本类型和 null
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理循环引用
if (map.has(obj)) {
return map.get(obj);
}
// 处理 Date
if (obj instanceof Date) {
return new Date(obj);
}
// 处理 RegExp
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 处理数组和普通对象
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
// 递归复制所有属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map);
}
}
return clone;
}
// 测试
const original = {
name: 'test',
nested: { value: 1 },
arr: [1, 2, { x: 3 }],
date: new Date(),
};
original.self = original; // 循环引用
const cloned = deepClone(original);
cloned.nested.value = 999;
console.log(original.nested.value); // 1 - 原对象不受影响
console.log(cloned.self === cloned); // true - 循环引用正确处理
JSON 方法的局限性
const obj = {
fn: function() {}, // 函数会丢失
undef: undefined, // undefined 会丢失
sym: Symbol('test'), // Symbol 会丢失
date: new Date(), // 变成字符串
reg: /test/g, // 变成空对象
};
const copy = JSON.parse(JSON.stringify(obj));
console.log(copy);
// { date: "2024-01-01T00:00:00.000Z", reg: {} }
关键点
- 浅拷贝只复制第一层,嵌套对象共享引用
- 深拷贝递归复制所有层级,完全独立
JSON.parse(JSON.stringify())简单但无法处理函数、undefined、Symbol、循环引用- 手写深拷贝需要用 WeakMap 处理循环引用
- 特殊对象(Date、RegExp、Map、Set)需要单独处理
目录