vue实现依赖收集
依赖收集的基本原理
Vue 的依赖收集基于观察者模式,通过 Object.defineProperty 或 Proxy 拦截数据的访问和修改。当数据被访问时,收集当前正在执行的依赖(如计算属性、模板渲染函数);当数据修改时,通知这些依赖进行更新。
核心实现步骤
定义 Dep 类
每个响应式数据属性对应一个 Dep 实例,用于管理依赖(即 Watcher 实例):
class Dep {
constructor() {
this.subscribers = new Set();
}
depend() {
if (activeWatcher) {
this.subscribers.add(activeWatcher);
}
}
notify() {
this.subscribers.forEach(watcher => watcher.update());
}
}
定义 Watcher 类
Watcher 表示一个依赖,通常是组件渲染函数或计算属性:

let activeWatcher = null;
class Watcher {
constructor(updateFn) {
this.updateFn = updateFn;
this.update();
}
update() {
activeWatcher = this;
this.updateFn();
activeWatcher = null;
}
}
实现响应式数据
通过 defineReactive 函数将普通对象转换为响应式对象:
function defineReactive(obj, key) {
const dep = new Dep();
let value = obj[key];
Object.defineProperty(obj, key, {
get() {
dep.depend(); // 收集当前活跃的 Watcher
return value;
},
set(newVal) {
if (newVal !== value) {
value = newVal;
dep.notify(); // 通知所有依赖更新
}
}
});
}
使用示例
创建响应式对象

const data = { count: 0 };
defineReactive(data, 'count');
创建依赖
当 data.count 被访问时,自动收集依赖:
new Watcher(() => {
console.log(`Count updated: ${data.count}`);
});
触发更新
修改 data.count 将自动触发 Watcher 的更新函数:
data.count++; // 输出 "Count updated: 1"
基于 Proxy 的实现(Vue 3)
Vue 3 使用 Proxy 替代 Object.defineProperty,核心逻辑类似但能拦截更多操作:
function reactive(obj) {
const depsMap = new Map();
return new Proxy(obj, {
get(target, key) {
let dep = depsMap.get(key);
if (!dep) {
dep = new Dep();
depsMap.set(key, dep);
}
dep.depend();
return target[key];
},
set(target, key, value) {
target[key] = value;
const dep = depsMap.get(key);
if (dep) dep.notify();
return true;
}
});
}
关键点说明
- 动态依赖收集:只有在数据被访问时才会收集当前活跃的
Watcher。 - 批量更新:Vue 实际实现中会使用异步队列(如
nextTick)优化多次数据变更的更新。 - 嵌套依赖:组件或计算属性可能形成嵌套的依赖关系,Vue 通过依赖树管理这种场景。






