定义

在 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 对象会被转换为字符串。
      • 循环引用会报错。
  • 递归实现
    • 可以处理各种数据类型,包括函数、Symbol、Date 等。
    • 需要考虑循环引用的问题。
function deepCopy(obj, cache = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
 
  if (cache.has(obj)) {
    return cache.get(obj); // 解决循环引用
  }
 
  const copy = Array.isArray(obj) ? [] : {};
  cache.set(obj, copy);
 
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key], cache);
    }
  }
 
  return copy;
}
 
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

应用场景

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

优缺点

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

相关概念

参考资料