定义
在 JavaScript 中,深拷贝和浅拷贝是针对引用数据类型(如对象和数组)的复制方式。它们的主要区别在于是否创建新的内存空间。
核心特点
- 浅拷贝 (Shallow Copy):
- 只复制指向对象的指针,而不复制对象本身。
- 新对象和原对象共享同一块内存空间。
- 修改新对象会影响原对象,反之亦然。
- 深拷贝 (Deep Copy):
- 创建一个全新的对象,复制原对象的所有属性和值。
- 新对象和原对象拥有独立的内存空间。
- 修改新对象不会影响原对象,反之亦然。
浅拷贝的实现方式
- Object.assign():只能拷贝第一层属性,如果属性是对象或数组,仍然是浅拷贝。
- 展开运算符 (…):与
Object.assign()类似,只能拷贝第一层属性。
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
shallowCopy.a = 3;
shallowCopy.b.c = 4;
console.log(obj.a); // 1
console.log(obj.b.c); // 4深拷贝的实现方式
- JSON.parse(JSON.stringify(obj)):
- 简单粗暴,但有局限性:
- 无法拷贝函数、Symbol、undefined。
- Date 对象会被转换为字符串。
- 循环引用会报错。
- 简单粗暴,但有局限性:
function deepCopy(obj){
return JSON.parse(JSON.stringify(obj))
}- 递归实现:
- 可以处理各种数据类型,包括函数、Symbol、Date 等。
- 需要考虑循环引用的问题。
- 需要考虑特殊对象类型(Date,RegExp,Map,Set,WeakMap,WeakSet)。
function completeDeepClone(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
// 使用Reflect.ownKeys获取所有属性
Reflect.ownKeys(obj).forEach(key => {
clone[key] = deepClone(obj[key], map);
});
return clone;
}
const obj = { a: 1, b: { c: 2 }, d: new Date() };
const deepCopyObj = deepCopy(obj);
deepCopyObj.a = 3;
deepCopyObj.b.c = 4;
console.log(obj.a); // 1
console.log(obj.b.c); // 2应用场景
- 浅拷贝:
- 复制简单对象或数组,且不需要修改原对象。
- 例如:复制配置对象。
- 深拷贝:
- 复制复杂对象或数组,且需要修改新对象而不影响原对象。
- 例如:复制用户数据、游戏状态。
优缺点
- 浅拷贝:
- 优点:速度快,内存占用少。
- 缺点:修改新对象会影响原对象。
- 深拷贝:
- 优点:修改新对象不会影响原对象。
- 缺点:速度慢,内存占用多。