JavaScript中的深浅拷贝

在JavaScript中,深浅拷贝是处理对象复制的重要概念,主要用于避免引用类型数据共享带来的副作用。以下从定义、区别、实现方法和注意事项进行详细讲解。

1. 浅拷贝(Shallow Copy)

  • 定义:创建一个新对象,只复制对象的第一层属性(基本类型值会被复制,引用类型值则复制其引用地址)。因此,如果原对象的属性包含嵌套对象,修改新对象的嵌套属性会影响原对象。

  • 实现方法

    • 对象浅拷贝

      • 使用 Object.assign():const newObj = Object.assign({}, originalObj);

      • 使用展开运算符(ES6):const newObj = { ...originalObj };

    • 数组浅拷贝

      • 使用 Array.from():const newArr = Array.from(originalArr);

      • 使用 slice():const newArr = originalArr.slice();

      • 使用展开运算符:const newArr = [...originalArr];

示例代码

javascript 复制代码
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
shallowCopy.b.c = 3; // 修改嵌套属性
console.log(obj.b.c); // 输出 3,原对象也被修改
  • 特点

    • 简单高效,适合拷贝简单结构。

    • 缺点:嵌套对象共享引用,可能导致意外修改。

2. 深拷贝(Deep Copy)

定义:创建一个新对象,并递归地复制所有层级属性(包括嵌套对象),使得新对象与原始对象完全独立。修改新对象不会影响原对象。

  • 实现方法

    • JSON方法(简单但有限制):

      • const newObj = JSON.parse(JSON.stringify(originalObj));

      • 缺点:无法复制函数、undefined、Symbol、循环引用或日期对象(会被转为字符串)。

  • 递归手动实现

    • 自定义函数处理各种类型:
javascript 复制代码
function deepClone(obj, map = new Map()) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (map.has(obj)) return map.get(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 newObj = deepClone(originalObj);

示例代码:

javascript 复制代码
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
deepCopy.b.c = 3; // 修改嵌套属性
console.log(obj.b.c); // 输出 2,原对象不受影响
  • 特点

    • 完全隔离数据,适合复杂对象。

    • 缺点:性能开销大(尤其递归深层次对象),需处理边界情况如循环引用。

structuredClone方法

在 JavaScript 中,structuredClone() 是现代浏览器和 Node.js(v17+)提供的原生深拷贝 API,专门用于解决传统深拷贝方法的局限性。以下是详细说明:

1. 为何需要 structuredClone
  • 传统深拷贝的不足

    • JSON.parse(JSON.stringify()) 会丢失函数、undefinedSymbol 等类型

    • 递归实现需手动处理循环引用、特殊对象(如 Date/Map/Set)

  • structuredClone 直接内置于 JavaScript 运行时,无需第三方库

2.核心功能与优势
  • 深拷贝实现:递归复制所有层级(包括嵌套对象、数组、Map、Set等),生成完全独立的新对象。

  • 支持复杂类型

    • ✅ 支持DateRegExpArrayBufferMapSet等类型(JSON方法会丢失这些类型)

    • ✅ 自动处理循环引用 (如obj.self = obj

    • ❌ 不支持函数、DOM节点、Error对象(会抛出DOMException

    • 语法简洁

javascript 复制代码
const original = { a: 1, b: new Date() };
const clone = structuredClone(original); // 一行代码完成深拷贝
3. 与传统方法的对比
方法 支持循环引用 保留特殊类型 性能 安全性
JSON.parse/stringify
递归手动实现 需额外处理
structuredClone

3. 关键区别与注意事项

  • 核心区别

    • 浅拷贝:只复制一层,嵌套对象共享引用。

    • 深拷贝:复制所有层级,嵌套对象独立。

  • 使用场景

    • 浅拷贝:状态管理(如React的浅比较)、简单数据传递。

    • 深拷贝:数据持久化、不可变数据更新(如Redux reducer)。

  • 常见陷阱

    • 循环引用:手动深拷贝需使用WeakMap或Map避免无限递归。

    • 性能:深拷贝大对象可能阻塞主线程,优先考虑浅拷贝或Immutable.js等库。

    • 类型兼容:JSON方法会丢失特殊类型(如函数),需手动处理。