javascript深拷贝是什么_如何实现对象和数组的深拷贝【教程】

10次阅读

深拷贝递归复制整个对象树,包括嵌套对象、dateregexp等,确保原对象与拷贝完全独立;jsON.stringify() + parse仅适用于纯数据且丢弃undefined/function/symbol等;手写需处理类型识别、特殊对象构造及循环引用;structuredClone()支持多类型但不兼容function/undefined/Symbol且有浏览器限制。

javascript深拷贝是什么_如何实现对象和数组的深拷贝【教程】

深拷贝到底在复制什么

深拷贝不是简单地复制变量值,而是递归地复制整个对象树——包括所有嵌套的对象、数组、Date、RegExp 等引用类型值。原始对象和拷贝对象完全独立,修改任一对象的任意层级属性,都不会影响另一个。

这和 Object.assign() 或展开运算符 {...obj} 的浅拷贝有本质区别:它们只复制第一层属性,内部嵌套的对象仍共享同一内存地址。

json.stringify() + JSON.parse() 为什么不能乱用

这是最常被误用的“深拷贝方案”,它只适用于纯数据对象(Plain Object)和数组,且有多个硬性限制:

  • undefinedfunctionSymbol 字段会被直接丢弃
  • Date 对象变成字符串(如 "2024-05-12T08:30:00.000Z"),丢失原型和方法
  • RegExp 变成空对象 {}
  • 循环引用会直接抛出 TypeError: Converting circular structure to JSON
  • map、Set、TypedArray、BigInt 等类型全部不支持

所以除非你 100% 确认输入是 JSON-safe 数据(比如后端返回的纯配置对象),否则不要把它当通用深拷贝手段。

立即学习Java免费学习笔记(深入)”;

手写递归深拷贝要注意哪些关键点

一个健壮的手写实现必须处理类型识别、特殊对象构造、循环引用检测三类问题:

  • Object.prototype.toString.call() 精确判断类型,而不是仅靠 typeofinstanceof
  • DateRegExpArray 等需分别用 new Date(obj)new RegExp(obj)Array.from(obj) 构造新实例
  • 必须用 WeakMap 缓存已遍历的对象引用,遇到重复出现的同一对象时直接返回缓存结果,避免无限递归
  • 普通对象使用 Object.create(Object.getPrototypeOf(obj)) 保持原型链,而不是简单 {}

示例片段(简化版):

function deepClone(obj, seen = new WeakMap()) {   if (obj === null || typeof obj !== 'object') return obj;   if (seen.has(obj)) return seen.get(obj);    const type = Object.prototype.toString.call(obj);   let cloned;    if (type === '[object Array]') {     cloned = [];   } else if (type === '[object Date]') {     cloned = new Date(obj);   } else if (type === '[object RegExp]') {     cloned = new RegExp(obj);   } else {     cloned = Object.create(Object.getPrototypeOf(obj));   }    seen.set(obj, cloned);   for (const key in obj) {     if (Object.hasOwn(obj, key)) {       cloned[key] = deepClone(obj[key], seen);     }   }   return cloned; }

用 structuredClone() 前先看浏览器兼容性

structuredClone() 是目前最接近“开箱即用”的标准方案,支持 MapSetDateRegExpArrayBuffer 等,也自动处理循环引用。

但它不是万能的:

  • 不支持 functionundefinedSymbol —— 遇到会直接报错 DataCloneError
  • node.js 直到 v17.0+ 才默认启用,v16 需加 --enable-structured-cloning 标志
  • chrome 98+、firefox 94+、safari 15.4+ 支持;IE 完全不支持
  • 无法自定义克隆逻辑(比如过滤某些字段或转换值)

如果项目需要兼容老浏览器,或需定制行为(例如忽略某些 key、转换日期格式),还是得回退到手写或第三方库(如 lodash.cloneDeep)。

循环引用、原型链、不可枚举属性、访问器属性(getter/setter)——这些细节一旦漏掉一个,就不是真正的深拷贝。别让“看起来没报错”骗过自己。

text=ZqhQzanResources