02.响应式变化
约 1013 字大约 3 分钟
2026-03-01
Vue3 响应式相较于 Vue2 是否有改变?
数据拦截:从
Object.defineProperty改为Proxy+Object.defineProperty- ref:Object.defineProperty + Proxy
- reactive:Proxy
创建响应式数据:
- Vue2:通过 data
- Vue3:通过 ref、reactive 等
依赖收集:
- Vue2:Watcher + Dep
- Vue3:WeakMap + Map + Set
- Vue3 依赖追踪粒度更细,更新控制更精确
Vue2 的响应式
采用数据劫持 + 观察发布者模式实现响应式
data 中的数据会通过
Object.defineProperty遍历生成getter/setter注
- 整个数据劫持触发时机在
beforeCreate之后、created之前。因此无法检测未来动态增加或删除的属性,但额外通过了$set和$delete - 这其中每一个响应式属性都会对应一个 Dep 实例,它是在
Observer中定义getter / setter时创建的,作为闭包变量存在
- 整个数据劫持触发时机在
每一个 组件 都对应一个
watcher,当 组件中的数据被访问时,依赖收集 Dep,当 数据发生变化时,通知观察者 watcher 进行派发更新注
Dep 即依赖管理器,核心功能
- 添加观察者:读取响应式属性时做依赖收集
- 通知观察者:属性改变时派发更新

Alt text watcher 会调用
update方法,通知组件重新渲染Dep 通知 watcher 后,若 watcher 立即执行会导致函数频繁运行、效率低下
state.a = "new data" state.b = "new data" state.c = "new data" state.d = "new data" // a、b、c、d 都记录依赖 → 触发 4 次更新watcher 收到通知后不立即执行,而是交给调度器。调度器维护执行队列,同一 watcher 在队列中只存在一次,通过
nextTick将 watcher 放入微队列执行。响应式数据变化时,render 的执行是异步的,且在微队列中整体流程
角色 说明 劫持数据 通过 Object.defineProperty做数据劫持,生成 getter/setter发布者 Dep 记录依赖(数据与 watcher 的映射),派发更新 观察者 Watcher 被 Dep 记录,数据变化时执行相应处理 
Alt text
Vue3 响应式
采用Proxy + 观察者模式,相较 Vue2 在数据拦截、创建方式、依赖收集三方面有变化
| 变化点 | Vue2 | Vue3 |
|---|---|---|
| 数据拦截 | Object.defineProperty | Proxy + Object.defineProperty |
| 创建响应式数据 | 通过 data | 通过 ref、reactive 等 |
| 依赖收集 | Watcher + Dep | WeakMap + Map + Set |
数据拦截:从
Object.defineProperty改为Proxy+Object.defineProperty注
Object.defineProperty针对对象特定属性的读写,新增/删除属性侦测不到;Proxy针对整个对象多种操作(读取、赋值、删除等),可侦测动态增删,多数场景性能更优创建响应式数据:从
data改为ref、reactive等ref 源码class RefImpl<T> { private _value: T private _rawValue: T public dep?: Dep = undefined public readonly __v_isRef = true constructor(value: T, public readonly __v_isShallow: boolean) { this._rawValue = __v_isShallow ? value : toRaw(value) this._value = __v_isShallow ? value : toReactive(value) } get value() { // 收集依赖 略 return this._value } set value(newVal) { // 略 } } export const toReactive = <T extends unknown>(value: T): T => isObject(value) ? reactive(value) : valuereactive 源码function createReactiveObject( target: Target, isReadonly: boolean, baseHandlers: ProxyHandler<any>, collectionHandlers: ProxyHandler<any>, proxyMap: WeakMap<Target, any>, ) { const proxy = new Proxy( target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers, ) proxyMap.set(target, proxy) return proxy } export function reactive(target: object) { return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap, ) }依赖收集:从 Watcher + Dep 改为 WeakMap + Map + Set
注
Vue2:每个响应式属性有一个 Dep,内部数组存储 watcher;属性变化时 dep 通知所有 watcher
Vue3:
WeakMap键为响应式对象,值为Map;Map 的键为属性,值为Set(存储 effect 函数)。依赖追踪粒度更细:Vue2 收集 Watcher(组件级),Vue3 收集副作用函数
