vue响应式核心是weakmap与map嵌套结构:weakmap以响应式对象为键存储depsmap,map以属性名为键存储依赖该属性的effect集合,effect自身维护deps集以便清理脏依赖。

Vue 的响应式数据追踪,核心在于“谁用了谁”这个关系的记录与维护。它不靠人工标记,而是通过一套自动化的数据结构,在读取时悄悄记下依赖,在修改时精准通知——而支撑这一切的,就是两个关键容器:WeakMap 和 Map 的嵌套组合。
WeakMap 存对象,保证不泄漏
每个被 reactive() 处理过的原始对象(比如 { count: 0 }),都会作为 键 存进一个全局的 reactiveMap: WeakMap 中。它的值,是另一个用于管理该对象内部属性依赖的 Map。
选择 WeakMap 的原因很实际:
- 键必须是对象,天然契合“目标对象”这一角色
- 它对键使用弱引用:当原始对象在其他地方不再被引用时,GC 可以安全回收它,连带其在 WeakMap 中的整个条目也会自动消失
- 避免因响应式系统长期持有对象引用而导致内存泄漏
Map 存字段,按 key 组织依赖
WeakMap 的值是一个 Map,我们常叫它 depsMap。这个 Map 的键是对象的属性名(如 'count'、'list'),值则是一个 Set,里面装着所有读取过该属性的副作用函数(effect)。
例如:
- 执行
effect(() => console.log(state.count))时,state.count被读取 → 触发track(state, 'count') -
track会找到reactiveMap.get(state)对应的depsMap - 再从
depsMap.get('count')拿到那个Set,把当前 effect 加进去
effect 自带 deps 集合,方便清理
每个通过 effect() 创建的副作用函数,自身也持有一个 deps: Set。这个集合里存的是它自己所依赖的所有 dep(即那些属性对应的 Set)。
这样设计的好处是:
- 当 effect 被重新执行前,可以先调用
cleanup(),把它之前收集的所有 dep 中的自己删掉 - 避免旧依赖残留,导致不该触发的时候还被通知(所谓“脏依赖”)
- 让依赖关系始终准确、可维护
整个结构就像一张三层索引表
你可以把它想象成这样一层层查下去:
- 第一层:WeakMap → 找到某个对象对应的依赖总表(depsMap)
- 第二层:Map(depsMap)→ 找到某个属性名(如
'name')对应的依赖集合(dep Set) - 第三层:Set(dep)→ 存着所有监听这个属性的 effect 函数
数据一变,顺着这张表反向查,就能立刻知道要通知谁,不遗漏、不误伤。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










