vue监听实现原理
Vue 监听实现原理
Vue 的监听机制主要通过 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)实现数据响应式。以下是核心原理的详细分析:

数据劫持(Vue 2.x)
Vue 2.x 使用 Object.defineProperty 劫持对象的属性访问和修改。通过为每个属性设置 getter 和 setter,在数据变化时触发依赖更新。

function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log('读取属性', key);
return val;
},
set(newVal) {
if (newVal !== val) {
console.log('更新属性', key);
val = newVal;
// 触发依赖更新
dep.notify();
}
}
});
}
- 依赖收集:在
getter中,当前正在执行的Watcher(如组件渲染函数)会被添加到依赖列表(Dep)中。 - 派发更新:在
setter中,通知所有依赖的Watcher执行更新。
代理模式(Vue 3.x)
Vue 3.x 改用 Proxy 实现更强大的响应式能力。Proxy 可以直接监听整个对象而非属性,并支持动态新增属性的监听。
const reactive = (target) => {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
trigger(target, key); // 派发更新
return true;
}
});
};
- 优势:无需递归遍历对象属性,性能更好;支持监听数组索引和
length变化。
依赖管理
- Dep 类:每个响应式属性对应一个
Dep实例,用于存储所有依赖的Watcher。 - Watcher 类:代表一个依赖(如组件渲染函数、计算属性),在数据变化时执行回调。
class Dep {
constructor() {
this.subscribers = new Set();
}
depend() {
if (activeWatcher) this.subscribers.add(activeWatcher);
}
notify() {
this.subscribers.forEach(watcher => watcher.update());
}
}
数组监听的特殊处理
Vue 2.x 通过重写数组的变异方法(如 push、pop)实现监听:
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift'].forEach(method => {
const original = arrayProto[method];
arrayMethods[method] = function(...args) {
const result = original.apply(this, args);
dep.notify(); // 手动触发更新
return result;
};
});
总结
- Vue 2.x 基于
Object.defineProperty,需显式声明响应式属性,对数组需特殊处理。 - Vue 3.x 基于
Proxy,支持全对象监听,性能更优,代码更简洁。 - 依赖收集和派发更新通过
Dep和Watcher协作完成。






