依赖项指因读取响应式数据而被自动关联的副作用函数,如组件渲染函数、computed getter、watcheffect 回调;作用域追踪通过全局临时变量 activeeffect 标记当前执行的响应式函数,在 get 拦截器中调用 track 将其加入对应属性的依赖集合,执行完即清空,确保依赖严格绑定运行时作用域。

Vue 响应式系统中的依赖项与作用域追踪,核心在于“读时登记、改时通知”,且严格绑定在响应式副作用执行的作用域内。它不是静态配置,而是运行时动态建立的映射关系。
依赖项(Dependencies)指什么?
依赖项不是数据本身,而是那些因读取响应式数据而被自动关联的副作用函数,比如:
- 组件的渲染函数(setup 中模板所用的 reactive/ref)
-
computed(() => state.a + state.b)内部封装的 getter 函数 -
watchEffect(() => console.log(state.count))创建的监听函数
普通 JavaScript 访问(如console.log(state.count))不触发收集,因为没有活跃的 effect 作为上下文。
作用域追踪如何工作?
Vue 用一个全局但临时的变量 activeEffect 标记当前正在执行的响应式函数。这个变量就像“当前工位号”:
- 进入
setup()渲染逻辑或computed/watchEffect回调时,Vue 把该函数设为activeEffect - 执行中访问
state.count,Proxy 的get拦截器调用track(state, 'count'),把activeEffect加入count的依赖集合 - 函数执行结束,
activeEffect被清空,避免污染后续逻辑
这保证了依赖只属于它实际运行的那个作用域,不同组件、不同 computed 互不干扰。
依赖存在哪里?不是挂在对象上
Vue 使用三层嵌套结构管理依赖,避免污染原始数据并支持自动回收:
- 外层
targetMap: WeakMap<object map></object>—— 键是原始对象,值是它的属性依赖图 - 中层
depsMap: Map<key set>></key>—— 键是属性名(如'count'),值是所有依赖它的 effect 集合 - 内层
dep: Set<reactiveeffect></reactiveeffect>—— 存储具体要通知的函数
这样设计让 state.info.name 和 state.list[0] 各自维护独立依赖列表,修改 name 不会误触发 list 相关逻辑。
为什么嵌套对象也自动响应?
关键在 get 拦截器里的递归代理逻辑:
- 读取
state.user.profile时,先拿到profile原始对象 - 立即对它调用
reactive(),返回已代理的新 proxy - 后续读
profile.avatar就自然走get + track流程
所以无需手动reactive(state.user.profile),深度响应是惰性、按需触发的。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










