什么是JavaScript的深拷贝_如何实现对象复制

深拷贝是创建完全独立的新对象,避免引用类型数据相互影响;因对象数组为引用类型,浅拷贝仅复制地址会导致原对象被意外修改;常用方法包括JSON法(限纯JSON)、structuredClone(推荐现代环境)、手写递归(可定制)和Lodash cloneDeep(全面稳定)。

JavaScript 中的深拷贝,是指创建一个全新对象,其内部所有嵌套的对象、数组等引用类型数据也都被递归复制,新对象与原对象完全独立,互不影响。

为什么需要深拷贝

因为 JavaScript 中对象和数组是引用类型。直接赋值(浅拷贝)只是复制了引用地址,修改新对象里的嵌套内容,原对象也会跟着变:

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = obj1; // 浅拷贝(其实是引用)
obj2.b.c = 99;
console.log(obj1.b.c); // 输出 99 —— 被意外改了

常见深拷贝方法及适用场景

没有一种方法完美适用于所有情况,需根据数据结构、是否含特殊值(如函数、undefined、Date、RegExp、Map、Set 等)来选择:

  • JSON.parse(JSON.stringify(obj)):最简单快捷,但只支持纯 JSON 数据(不支持函数、undefined、Symbol、Date、RegExp、NaN、Infinity、循环引用)。适合配置对象、简单数据传输。
  • structuredClone()(现代浏览器 & Node.js 17.0+):原生支持深拷贝,能处理 Date、RegExp、Map、Set、ArrayBuffer、TypedArray 等,且支持循环引用。推荐在兼容环境下优先使用:
    const newObj = structuredClone(originalObj);
  • 手写递归函数:可控性强,可定制处理逻辑(比如跳过某些字段、转换日期格式),但需手动处理边界情况(null、Date、RegExp、循环引用等)。适合有特殊需求或需兼容老环境的项目。
  • Lodash 的 _.cloneDeep():成熟稳定,覆盖绝大多数边缘情况,包括循环引用、各种内置类型、不可枚举属性等。适合中大型项目,引入依赖可接受时使用。

手写简易深拷贝示例(不含循环引用处理)

供理解原理,生产环境建议用 structuredClone 或 Lodash:

function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  const cloned = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key]);
    }
  }
  return cloned;
}

注意容易忽略的点

  • 函数、undefined、Symbol 在 JSON 方法中会丢失;
  • 原型链上的属性不会被拷贝(深拷贝关注的是自有可枚举属性);
  • DOM 元素、window 等宿主对象无法安全深拷贝,通常也不该这么做;
  • 性能上,深拷贝开销随嵌套深度和数据量增大而上升,大数据量场景要考虑是否真的需要深拷贝,或改用不可变更新策略(如 Immer)。