vue 监听实现原理
Vue 监听实现原理
Vue 的监听机制主要依赖于响应式系统,通过 Object.defineProperty 或 Proxy 实现数据劫持,结合观察者模式(Observer/Watcher/Dep)完成依赖收集和派发更新。
核心实现
数据劫持
- Vue 2.x 使用
Object.defineProperty递归遍历对象的属性,将其转换为 getter/setter。 - Vue 3.x 改用
Proxy代理整个对象,无需递归初始化,性能更高。
// Vue 2.x 数据劫持示例
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log('收集依赖');
return val;
},
set(newVal) {
if (newVal === val) return;
console.log('触发更新');
val = newVal;
}
});
}
依赖收集与派发更新
- 每个响应式属性关联一个
Dep实例(依赖管理器)。 - 在 getter 中调用
dep.depend()收集当前 Watcher(如模板渲染、计算属性等)。 - 在 setter 中调用
dep.notify()通知所有 Watcher 执行更新。
class Dep {
constructor() {
this.subs = [];
}
depend() {
if (targetWatcher) {
this.subs.push(targetWatcher);
}
}
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
监听 API 实现
watch 和 computed
watch通过创建 Watcher 实例,指定回调函数,当依赖变化时执行回调。computed是懒执行的 Watcher,依赖变化时标记为脏值,下次访问时重新计算。
// 简化的 Watcher 实现
class Watcher {
constructor(vm, expOrFn, callback) {
this.vm = vm;
this.getter = parseExpression(expOrFn);
this.callback = callback;
this.value = this.get();
}
get() {
pushTarget(this); // 设置当前 Watcher
const value = this.getter.call(this.vm);
popTarget();
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.callback.call(this.vm, this.value, oldValue);
}
}
性能优化
- 异步更新队列:Vue 将多次数据变更合并为一次 DOM 更新(通过
nextTick实现)。 - 组件级更新:每个组件对应一个渲染 Watcher,减少不必要的子组件更新。
通过以上机制,Vue 实现了高效的数据监听和视图更新。







