Vue数据依赖实现
Vue 数据依赖实现原理
Vue 的数据依赖实现基于响应式系统,核心是通过 Object.defineProperty(Vue 2)或 Proxy(Vue 3)劫持数据变化,结合观察者模式(Watcher)和依赖收集(Dep)完成。
核心模块
-
Observer
递归遍历数据对象,为每个属性添加 getter/setter。
getter 触发依赖收集,setter 触发通知更新。 -
Dep(依赖收集器)
每个属性对应一个 Dep 实例,用于存储所有依赖该属性的 Watcher。
-
Watcher(观察者)
代表一个依赖,当数据变化时触发回调(如视图更新)。
代码示例(Vue 2 实现)
class Dep {
constructor() {
this.subs = new Set();
}
addSub(watcher) {
this.subs.add(watcher);
}
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
function observe(obj) {
Object.keys(obj).forEach(key => {
let value = obj[key];
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) dep.addSub(Dep.target);
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
dep.notify();
}
});
});
}
class Watcher {
constructor(getter) {
this.getter = getter;
this.get();
}
get() {
Dep.target = this;
this.value = this.getter();
Dep.target = null;
}
update() {
this.get();
}
}
流程说明
-
初始化阶段
observe(data)将数据转为响应式,每个属性绑定 Dep。
-
依赖收集
模板编译或computed触发 getter,当前 Watcher 被记录到 Dep 中。 -
触发更新
数据修改时 setter 调用dep.notify(),通知所有 Watcher 执行更新。
Vue 3 优化
- 使用
Proxy代理整个对象,无需递归遍历。 - 惰性响应:仅在访问属性时触发依赖收集。
- 性能提升:减少初始化开销,支持动态新增属性。
注意事项
- 数组需特殊处理(重写变异方法如
push/pop)。 - 对象新增属性需用
Vue.set(Vue 2)或直接赋值(Vue 3)。






