Vue3用WeakMap缓存原始对象与Proxy代理映射,核心是防止内存泄漏:其弱引用特性确保组件卸载后对象被GC自动回收,避免普通Map强引用导致的依赖残留。

Vue3 用 WeakMap 来缓存原始对象和它对应的 Proxy 代理之间的映射关系,核心目的不是“提速”,而是“不泄漏”——让响应式对象在组件卸载后能被垃圾回收器自动清理,无需手动干预。
WeakMap 存什么?为什么非它不可?
它只存一层关键映射:原始对象(target)→ 它的 Proxy 实例。比如你对 { count: 0 } 调用 reactive(),Vue 就把该对象作为 key、生成的 Proxy 作为 value 存进 WeakMap。
- 同一对象多次调用
reactive()时,WeakMap 可快速命中并复用已有代理,避免重复代理和递归陷阱 - 键只能是对象,且是弱引用——这意味着它不参与 JavaScript 的可达性判定
- 只要这个原始对象在其他地方失去所有强引用(比如组件实例被销毁、变量设为
null),GC 就会立刻回收它,连带 WeakMap 中的条目也一并消失
它怎么防止内存泄漏?对比普通 Map 就明白了
如果改用普通 Map 做缓存,问题就来了:Map 对 key 是强引用。即使组件已卸载,Map 还牢牢“抓着”那个原始对象,导致对象无法被 GC 回收,依赖它的 effect、Proxy、甚至整个组件状态都滞留在内存里。
- DOM 元素被移除后,若其响应式状态还被 Map 强持有,就会变成“幽灵节点”
- 路由切换、
v-if隐藏组件时,残留的响应式数据会持续占用内存,长期运行可能引发卡顿 - WeakMap 不阻止回收,所以 Vue 不需要你在
onUnmounted里手动清缓存
WeakMap 在依赖收集结构中处于什么位置?
它是整个响应式依赖链的“总开关”。Vue 内部实际采用三层嵌套结构:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
立即学习“前端免费学习笔记(深入)”;
- 外层:
const targetMap = new WeakMap()—— 映射原始对象 → 属性依赖表 - 中层:
const depsMap = new Map()—— 映射属性名(key)→ effect 集合 - 内层:
const effects = new Set()—— 存储依赖该属性的所有副作用函数
只有最外层用 WeakMap;中间两层虽是强引用,但它们的生命周期完全由外层决定——一旦原始对象被 GC 回收,整条链自然断开,不会留下悬挂依赖。
它和循环引用有关系吗?
WeakMap 本身不直接解决循环引用,但它为安全遍历提供了基础保障。Vue 在深度响应化时,会配合 WeakSet 记录已访问对象,防止重复进入同一对象造成栈溢出;而 WeakMap 确保:哪怕遍历过程中生成了大量代理,只要原始对象被释放,所有关联的代理、依赖、effect 都会被一并清理干净。

















