vue watch 实现原理
Vue Watch 实现原理
Vue 的 watch 功能用于监听数据变化并执行回调函数。其核心实现基于 Vue 的响应式系统,依赖 Object.defineProperty 或 Proxy(Vue 3)进行数据劫持,并通过依赖收集和派发更新机制实现监听。
依赖收集与派发更新
当初始化 watch 时,Vue 会将监听的回调函数作为依赖收集到当前数据的依赖列表中。数据变化时,触发 setter 或 Proxy 的拦截逻辑,通知所有依赖(Watcher 实例)执行回调。
Watcher 类
Vue 内部通过 Watcher 类实现监听逻辑。Watcher 分为三类:渲染 Watcher、计算属性 Watcher 和用户自定义 Watcher(即 watch 选项)。watch 的每个监听项会创建一个 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); // 执行回调
}
}
监听触发流程
- 初始化阶段:解析
watch选项,为每个监听属性创建Watcher实例,并设置回调函数。 - 依赖收集:首次调用
Watcher.get()时,触发监听属性的getter,将当前 Watcher 添加到依赖列表中。 - 数据更新:监听属性被修改时,触发
setter或Proxy拦截,调用依赖列表中所有 Watcher 的update方法。 - 回调执行:
Watcher.update()对比新旧值,若变化则执行用户定义的回调函数。
深度监听实现
当设置 deep: true 时,Vue 会递归遍历监听对象的所有子属性,为每个子属性触发 getter,从而收集依赖。
// 伪代码:深度监听
function traverse(val) {
if (typeof val !== 'object') return;
for (const key in val) {
traverse(val[key]); // 递归触发子属性的 getter
}
}
立即触发与旧值获取
immediate: true:初始化时直接调用一次回调函数。- 旧值通过
Watcher实例的this.value缓存,在update时作为参数传递给回调。
Vue 3 的优化
Vue 3 使用 Proxy 替代 Object.defineProperty,解决了数组和新增属性的监听问题。watch 的实现改为基于 effect 和 ReactiveEffect 类,原理类似但更高效。







