vue组件watch实现原理
Vue 组件 watch 实现原理
Vue 的 watch 功能用于监听数据变化并执行回调函数。其核心原理基于 Vue 的响应式系统和依赖收集机制。
响应式系统基础
Vue 通过 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现数据劫持。当数据被访问时,依赖会被收集;当数据被修改时,依赖会被通知并触发更新。
watch 的工作流程
-
初始化监听
在组件初始化阶段,Vue 会遍历watch选项中定义的属性,为每个属性创建一个Watcher实例。这个Watcher会记录回调函数和监听的目标路径。 -
依赖收集
当首次执行watch时,会读取被监听属性的值,触发其getter。此时,Watcher会被添加到该属性的依赖列表中(即Dep实例的订阅者列表)。 -
触发回调
当被监听的属性值发生变化时,会触发setter,通知所有订阅该属性的Watcher执行更新。Watcher会执行回调函数,并传入新值和旧值。
源码关键逻辑(Vue 2 示例)
// 简化版 Watcher 实现
class Watcher {
constructor(vm, expOrFn, cb, options) {
this.vm = vm;
this.cb = cb;
this.getter = parsePath(expOrFn); // 解析属性路径(如 'a.b.c')
this.value = this.get(); // 触发依赖收集
}
get() {
pushTarget(this); // 将当前 Watcher 设置为全局正在计算的 Watcher
const value = this.getter.call(this.vm, this.vm); // 读取属性值,触发 getter
popTarget(); // 恢复之前的 Watcher
return value;
}
update() {
const oldValue = this.value;
this.value = this.get(); // 重新获取新值
this.cb.call(this.vm, this.value, oldValue); // 执行回调
}
}
深层监听与立即执行
deep: true
递归遍历监听对象的所有子属性,为每个子属性绑定同样的依赖收集逻辑。immediate: true
在初始化时立即执行一次回调,此时旧值为undefined。
Vue 3 的优化
Vue 3 改用 Proxy 实现响应式,watch 通过 effect 和 ReactiveEffect 实现类似的依赖追踪,逻辑更简洁且性能更好。
注意事项
- 避免在回调中修改监听的数据,可能导致无限循环。
- 对于复杂对象,使用
deep监听可能带来性能开销,建议明确指定需要监听的子属性。







