Vue响应式系统由数据劫持、依赖收集和派发更新三步闭环构成:Vue2用Object.defineProperty劫持属性,Vue3用Proxy代理整个对象;访问数据时收集依赖,修改时通知所有关联effect异步更新视图。

Vue 响应式系统不是魔法,而是一套严密协作的机制:数据一变,视图立刻感知并重绘,整个过程由 reactive(或 Observer)→ 依赖收集 → effect / Watcher 触发更新 三步闭环完成。
数据劫持:让普通对象“开口说话”
Vue 要监听数据变化,首先得“听得到”。这靠的是底层的数据劫持:
- Vue 2 用
Object.defineProperty给每个属性加 get/set —— 读取时触发依赖收集,赋值时触发更新通知; - Vue 3 改用
Proxy代理整个对象,不仅能拦截属性读写,还能监听新增、删除、数组索引、length 变化等,能力更完整; - 对嵌套对象和数组,会递归处理(Vue 2 中 observe 递归调用 defineReactive;Vue 3 中 reactive 内部自动 proxy 深层结构);
-
ref是特例:它本质是带 .value 的响应式包装,内部仍基于 Proxy 或 defineProperty,但对外暴露简洁 API。
依赖收集:谁在用这个数据,当场记下
光劫持没用,得知道“谁关心它”。这个过程发生在视图首次渲染或计算属性求值时:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 当模板里写
{{ state.count }},执行 render 函数就会访问state.count; - 访问触发 reactive 的
get拦截器,此时会检查当前是否有活跃的副作用(effect),比如渲染用的renderEffect; - 有则调用
track(),把该 effect 记入count对应的依赖集合(Dep 或 ReactiveEffect 的 deps 数组); - 一个数据可被多个地方使用(如模板中用了两次 count),但依赖只收集一次,靠 Set 去重避免冗余。
派发更新:数据变了,精准通知所有依赖者
当你执行 state.count++,真正的更新链才启动:
立即学习“前端免费学习笔记(深入)”;
- 赋值触发
set(Vue 2)或settrap(Vue 3),确认值确实变化后,进入更新流程; - 找到该属性关联的依赖集合,遍历所有 effect(包括渲染 effect、watch effect、computed effect);
- 不是立刻执行,而是将 effect 推入异步更新队列(queueJob),实现批量合并 —— 同一轮事件循环中多次修改 count,只触发一次视图重绘;
- 等到 nextTick 微任务阶段,清空队列,依次执行 effect.run(),其中渲染 effect 会重新调用 render 函数生成新 vnode,再通过 patch 算法比对并更新真实 DOM。
配套机制:让响应式更健壮、更高效
除了主干流程,还有几个关键支撑点:
- computed 缓存:基于 Watcher 实现,带 dirty 标记。依赖未变时直接返回缓存值,避免重复计算;
- watch 清理:watch 回调返回的清理函数,在下次回调前自动执行,常用于清除定时器、取消请求;
- 依赖清理:组件卸载时,所有 effect 自动调用 cleanup,从对应 Dep 的 subs 中移除自己,防止内存泄漏;
-
只读与浅响应:
readonly()和shallowRef()等 API 提供细粒度控制,避免不必要的深层劫持开销。

















