深拷贝默认全量递归复制,生成完全独立副本;结构共享是不可变数据结构为优化性能主动设计的替代方案,仅在修改路径上新建节点,其余复用原引用。

深拷贝本身不天然具备结构共享——它默认是“全量递归复制”,而结构共享是不可变数据结构(如 Immutable.js、Immer)为解决深拷贝性能瓶颈所引入的主动设计策略。理解这一点,关键在于区分“行为目标”和“实现机制”:深拷贝要的是完全独立副本,结构共享要的是最小化复制+逻辑不可变。
结构共享不是深拷贝的子集,而是替代方案
传统深拷贝(如 JSON.parse(JSON.stringify(obj)) 或 structuredClone)会遍历每一层嵌套,为每个对象/数组创建全新内存实例。无论是否修改,它都做同样多的事。而结构共享型不可变更新(如 Immer 的 produce)只在你真正写入的路径上创建新节点,其余未触及的分支直接复用原引用。
- 例如:
state.user.profile.address.city = 'Beijing'→ 只新建address对象和city属性,user和profile仍指向原对象 - 原始 state 和新 state 共享 90% 以上内存,但对外表现为两个完全独立、互不影响的值
Immer 如何在 JS 原生限制下模拟结构共享
JavaScript 没有语言级不可变支持,Immer 用代理(Proxy)+ 懒快照(lazy copying)达成近似效果:
- 调用
produce(base, fn)时,Immer 包裹 base 为 Proxy,所有读操作透传,写操作被拦截并标记“待变更” - fn 执行完毕后,Immer 仅对被修改的路径做浅拷贝(如
{...obj}),深层未改部分保持引用不变 - 最终返回的新对象,与原对象之间形成“树状差异图”,共享未变子树
对比:什么时候该用真深拷贝,什么时候用结构共享
选型取决于目的而非“听起来更高级”:
- 需要彻底隔离副作用(如跨线程传递、存档快照、防外部篡改)→ 用
structuredClone或成熟深拷贝库 - 只是在 reducer / 状态更新中避免意外修改,且希望高效、可预测 → Immer 的结构共享更轻量、更符合函数式习惯
- 嵌套极深但修改极少(如配置树、表单数据)→ 结构共享节省大量内存和时间;反之,若每次都要改顶层字段,收益变小
一个直观类比
想象编辑一本纸质书:
- 深拷贝 = 找复印机,把整本书每一页都复印一遍,再拿红笔在复印件上改 —— 安全但耗纸、费时
- 结构共享(Immer) = 把原书摊开,只复印你准备涂改的那几页,其他页继续用原书 —— 新旧“书”逻辑上不同,但共用大部分纸张

















