vue 监听实现原理
Vue 监听实现原理
Vue 的监听机制主要依赖于响应式系统和依赖收集,核心是通过 Object.defineProperty 或 ES6 的 Proxy 实现数据劫持,结合发布-订阅模式完成数据与视图的绑定。
响应式数据劫持
对于对象属性,Vue 2.x 使用 Object.defineProperty 将属性转为 getter/setter,在 getter 中收集依赖(Watcher),在 setter 中触发更新。Vue 3.x 改用 Proxy 代理整个对象,拦截更全面(如数组变化、新增属性)。

// Vue 2.x 简化实现
function defineReactive(obj, key) {
let value = obj[key];
const dep = new Dep(); // 依赖收集器
Object.defineProperty(obj, key, {
get() {
if (Dep.target) dep.depend(); // 收集当前 Watcher
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
dep.notify(); // 通知更新
}
});
}
依赖收集与派发更新
每个响应式属性关联一个 Dep 实例(依赖收集器)。当组件渲染时,触发属性的 getter,将当前 Watcher(渲染器或用户自定义 watcher)存入 Dep 中。属性变化时,通过 setter 触发 Dep.notify(),通知所有 Watcher 执行更新。
class Dep {
constructor() {
this.subs = [];
}
depend() {
this.subs.push(Dep.target);
}
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
Watcher 的作用
Watcher 是观察者,分为渲染 Watcher(组件更新)、计算属性 Watcher 和用户自定义 Watcher(watch 选项)。初始化时通过 get() 方法主动触发依赖收集,后续数据变化时通过 update() 触发重新计算或渲染。

class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this; // 标记当前 Watcher
const value = this.getter.call(this.vm, this.vm);
Dep.target = null; // 收集完成后清除
return value;
}
update() {
this.run();
}
run() {
const value = this.get();
if (value !== this.value) {
this.cb.call(this.vm, value, this.value);
}
}
}
异步更新队列
Vue 通过异步队列(如 Promise.then、MutationObserver)批量处理数据变更的 Watcher 更新,避免重复渲染。同一事件循环内的多次数据修改只会触发一次组件更新。
function queueWatcher(watcher) {
if (!flushing) {
queue.push(watcher);
}
nextTick(flushSchedulerQueue); // 下一 tick 执行更新
}
总结
Vue 的监听实现核心是:
- 数据劫持拦截读写操作
- 依赖收集建立数据与 Watcher 的关联
- 派发更新时通过异步队列优化性能
- 结合虚拟 DOM 差异更新实现高效渲染






