定义

在 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

应用场景

  • 浅拷贝
    • 复制简单对象或数组,且不需要修改原对象。
    • 例如:复制配置对象。
  • 深拷贝
    • 复制复杂对象或数组,且需要修改新对象而不影响原对象。
    • 例如:复制用户数据、游戏状态。

优缺点

  • 浅拷贝
    • 优点:速度快,内存占用少。
    • 缺点:修改新对象会影响原对象。
  • 深拷贝
    • 优点:修改新对象不会影响原对象。
    • 缺点:速度慢,内存占用多。

相关概念

参考资料