Vue.js 响应式系统使用 WeakMap 实现对象级依赖收集,因其弱引用特性可避免内存泄漏;外层 WeakMap 以响应式对象为键、Map 为值,记录各属性对应的副作用函数集合;依赖在 Proxy 的 get 拦截器中自动收集。

Vue.js 的响应式系统依赖 WeakMap 实现高效、自动的依赖收集,核心在于它能以对象为键、安全地建立“对象 → 依赖关系”的映射,同时避免内存泄漏。
WeakMap 是什么?为什么 Vue 选它而不是普通 Map?
WeakMap 是 JavaScript 内置的集合类型,只接受对象(Object、Array、Map 等)作为键,且对键是弱引用——即不阻止垃圾回收机制释放该对象。这恰好契合响应式场景:
- 响应式对象(如
data中的普通对象)天然适合作为 WeakMap 的键; - 当组件卸载、响应式对象不再被任何地方引用时,WeakMap 中对应的条目会自动失效,无需手动清理;
- 若用普通
Map,键对象长期持有引用,容易造成内存泄漏。
WeakMap 在依赖收集中的实际结构
Vue 3 的响应式系统(基于 Proxy)内部使用一个全局的 targetMap: WeakMap<any map symbol set>>></any>:
-
外层 WeakMap 键:原始响应式对象(如
{ count: 1 }); -
值:一个
Map,以属性名('count')为键,对应所有依赖该属性的副作用函数(effect)集合; - 例如:
targetMap.get(obj)?.get('count')返回所有监听obj.count变化的 effect。
依赖收集发生在哪里?WeakMap 如何被触发?
在 get 拦截器中完成收集:
立即学习“前端免费学习笔记(深入)”;
- 访问响应式对象属性时(如
obj.count),触发Proxy的get; - 此时检查当前是否有正在执行的 activeEffect(即当前运行的副作用函数);
- 若有,则通过
targetMap.get(target)获取该对象的依赖表,再用.get(key)找到对应属性的 effect 集合,把activeEffect加进去; - 整个过程依赖 WeakMap 快速定位对象级依赖表,且不干扰对象生命周期。
WeakMap 的局限与 Vue 的应对
WeakMap 本身不能遍历、不能查键是否存在,也不支持非对象键——这限制了它直接存储数组索引或原始值依赖:
- 数组响应式靠重写
push/pop等方法 + 特殊处理length和索引,其依赖存于对象包装器(Array实例)的 WeakMap 条目中; - 基本类型(如
ref(1))不进 WeakMap,而是用RefImpl类自身维护dep: Set; - 所以 WeakMap 主力服务
reactive()创建的对象/数组,不是响应式系统的全部。


















