JavaScript深浅拷贝的本质差异在于内存行为:基本类型值存栈中,拷贝即复制独立值;引用类型变量存栈中地址,指向堆中真实数据,浅拷贝仅复制地址导致共享堆内存,深拷贝则在堆中新建完整副本实现彻底隔离。

画 JS 浅拷贝与深拷贝的思维导图,关键不是堆满术语,而是抓住“内存行为差异”这一根主线,把拷贝动作和数据类型、内存结构、实际影响串起来。下面分四块直接展开,每块都是导图里该放的核心分支。
一、先标清两类数据在内存中怎么存
这是所有拷贝逻辑的起点,不讲清楚这里,后面全飘。
- 基本类型(string/number/boolean/null/undefined/symbol):值直接存在栈里,拷贝就是复制一份新值,彼此完全独立
- 引用类型(object/array/function/date/regExp等):变量存的是指向堆内存的地址,拷贝默认只复制这个地址,不是复制堆里的内容
- String 虽是引用类型,但因不可变+常量池机制,多数场景表现得像基本类型——这点要单独加个备注框
二、浅拷贝:只拷第一层,引用地址照搬
核心特征:修改嵌套对象属性,原对象跟着变。
- 常见方法:Object.assign({}, obj)、[...arr]、Array.from(arr)、structuredClone()(仅限可序列化值)
- 注意陷阱:Object.assign(target, source) 的 target 如果传已有对象,会改原对象;必须用空对象做第一参数
- 典型失效场景:对象里有 date、regExp、function、undefined、NaN、Symbol 或循环引用——这些浅拷贝都处理不了
三、深拷贝:堆里内容也翻一份,彻底隔离
目标是让新对象和原对象从顶层到底层,完全互不影响。
- JSON 方案:JSON.parse(JSON.stringify(obj)) —— 快但限制多:丢函数、undefined、Symbol、Date 变字符串、NaN 变 null、无法处理循环引用
- structuredClone():现代浏览器原生支持,能处理 Map/Set/Date/RegExp/Blob 等,但暂不支持函数和某些特殊对象,且不能跨 iframe 使用
- 手写递归函数:判断类型 → 基本类型直接返回,引用类型新建对应结构 → 逐层递归拷贝;需额外处理循环引用(用 WeakMap 记录已拷贝对象)
四、怎么选?看场景再决定
没有银弹方案,选错可能白忙活,甚至埋坑。
- 只读配置对象、纯数据列表 → 浅拷贝够用,快又轻量
- 要编辑嵌套结构、做撤销/重做、状态快照 → 必须深拷贝,优先试 structuredClone,不行再上手写版
- 老项目兼容 IE 或需精细控制 → JSON 方案 + 预处理字段,或引入 lodash.cloneDeep
- 遇到循环引用、大量数据、性能敏感场景 → 别硬套通用深拷贝,考虑 Immutable.js 或结构共享策略











