vue watch 实现 原理
Vue Watch 实现原理
Vue 的 watch 功能用于监听数据变化并执行回调函数。其核心原理基于 Vue 的响应式系统,依赖 Object.defineProperty 或 Proxy(Vue 3)实现数据劫持,并结合依赖收集和派发更新机制。
响应式系统基础
Vue 的响应式系统通过以下步骤实现:
- 数据劫持:使用
Object.defineProperty(Vue 2)或Proxy(Vue 3)拦截数据的读取和修改操作。 - 依赖收集:在数据被访问时,收集当前正在计算的依赖(如
watch回调)。 - 派发更新:在数据被修改时,通知所有依赖执行更新。
Watch 的工作流程
-
初始化阶段
当在 Vue 实例中定义watch时,Vue 会遍历watch的配置项,为每个被监听的数据创建一个Watcher实例。new Vue({ data: { count: 0 }, watch: { count(newVal, oldVal) { console.log('count changed:', oldVal, '->', newVal); } } }); -
依赖收集
Watcher实例会在初始化时调用get方法,触发被监听数据的getter,从而将当前Watcher添加到依赖列表中(Dep 的 subs 数组)。 -
数据变化触发回调
当被监听的数据被修改时,会触发setter或Proxy的拦截逻辑,通知依赖列表中的所有Watcher执行update方法。Watcher的update方法会调用回调函数,并传入新值和旧值。
源码核心逻辑(Vue 2)
-
Watcher 类
Watcher是watch的核心实现,负责管理依赖和回调执行。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 设置为全局正在计算的依赖 const value = this.getter.call(this.vm, this.vm); // 触发 getter popTarget(); // 恢复之前的依赖 return value; } update() { const oldValue = this.value; this.value = this.get(); // 重新获取值 this.cb.call(this.vm, this.value, oldValue); // 执行回调 } } -
依赖管理(Dep 类)
每个响应式数据属性都有一个Dep实例,用于管理依赖。class Dep { constructor() { this.subs = []; // 存储 Watcher 实例 } depend() { if (Dep.target) { this.subs.push(Dep.target); // 收集依赖 } } notify() { this.subs.forEach(watcher => watcher.update()); // 通知更新 } }
深度监听和立即执行
-
深度监听(deep: true)
通过递归遍历对象的所有属性,为每个子属性绑定Watcher。if (this.deep) { traverse(value); // 递归触发子属性的 getter } -
立即执行(immediate: true)
在Watcher初始化时直接调用回调。if (options.immediate) { cb.call(vm, this.value); }
Vue 3 的改进
Vue 3 使用 Proxy 替代 Object.defineProperty,解决了以下问题:
- 无需递归劫持对象,
Proxy可以动态监听新增属性。 - 性能更好,避免了 Vue 2 中全量递归的缺陷。
总结
Vue 的 watch 机制依赖于响应式系统的核心设计:
- 通过
Watcher和Dep管理依赖关系。 - 数据变化时触发
Watcher回调。 - 支持深度监听和立即执行等高级功能。







