vue 3响应式系统用weakmap+map嵌套结构实现依赖收集,weakmap存对象到map的映射,map存属性到依赖set的映射,weakmap确保对象被gc时不泄漏内存。

为什么用 WeakMap?
因为响应式对象可能是临时创建、随时被 GC 的普通对象(比如组件作用域里的局部对象)。WeakMap 的键是弱引用,不阻止垃圾回收,避免内存泄漏——这点对 Vue 的响应式代理(Proxy)非常关键。
核心结构:WeakMap 存对象,Map 存属性依赖
Vue 3 的依赖收集逻辑大致如下:
- 外层用
WeakMap:键是原始响应式对象(target),值是另一个Map - 内层
Map:键是属性 key(字符串或 Symbol),值是Set类型的依赖集合(即触发该 key 变化时要执行的 effect 函数) - 当读取响应式对象某个属性(如
obj.count)时,会通过track(target, 'get', key)收集当前 activeEffect - 当修改属性(如
obj.count = 5)时,调用trigger(target, 'set', key)遍历并执行对应 Set 中的所有 effect
简化版实现示意(非 Vue 源码,仅说明原理)
下面是一个极简模拟,突出 WeakMap 的作用位置:
const targetMap = new WeakMap() // ✅ 外层:对象 → depsMap
function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
deps.add(activeEffect)
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const deps = depsMap.get(key)
if (deps) deps.forEach(effect => effect())
}
注意:targetMap 是 WeakMap,保证 target 被销毁后整个 depsMap 可被 GC;而内层的 Map 和 Set 是强引用,确保依赖能正确触发。
WeakMap 在 Vue 3 中的实际用途不止依赖收集
除了 targetMap,Vue 还用 WeakMap 做其他弱引用缓存:
-
reactiveMap:缓存已代理过的普通对象 → Proxy 实例,避免重复代理 -
readonlyMap:类似,用于只读代理缓存 -
rawToReactive/reactiveToRaw:在响应式对象与原始对象之间双向查找(例如toRaw()内部就靠它)
常见误区提醒
别误以为 WeakMap 里直接存了 effect 函数——它存的是“属性级依赖表”(Map);也别试图遍历 WeakMap 查看依赖,它是不可枚举的;更不要手动往 WeakMap 里塞非对象键(会报错)。
响应式是否生效,关键不在 WeakMap 本身,而在 track 是否被读取触发、activeEffect 是否存在、以及 trigger 是否覆盖了正确的 key —— WeakMap 只是让这套机制对内存更友好。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











