vue实现依赖收集
Vue 依赖收集实现原理
Vue 的依赖收集机制是其响应式系统的核心,通过以下方式实现:
依赖收集的基本流程
-
Observer 数据劫持
Vue 通过Object.defineProperty或Proxy劫持对象的属性访问。在getter中触发依赖收集,在setter中触发更新通知。 -
Dep 依赖管理类
每个响应式属性对应一个Dep实例,用于存储所有依赖该属性的Watcher(即订阅者)。
关键方法:depend():将当前Watcher添加到依赖列表。notify():通知所有依赖的Watcher更新。
-
Watcher 订阅者
代表一个依赖项(如组件渲染函数、计算属性等),在初始化时会触发getter,从而将自身添加到Dep的订阅列表中。
代码实现示例
// 简化版 Dep 类
class Dep {
constructor() {
this.subscribers = new Set();
}
depend() {
if (activeWatcher) {
this.subscribers.add(activeWatcher);
}
}
notify() {
this.subscribers.forEach(watcher => watcher.update());
}
}
// 全局变量记录当前运行的 Watcher
let activeWatcher = null;
// 简化版 Watcher 类
class Watcher {
constructor(updateFn) {
this.updateFn = updateFn;
this.update();
}
update() {
activeWatcher = this;
this.updateFn();
activeWatcher = null;
}
}
// 响应式数据劫持
function observe(obj) {
Object.keys(obj).forEach(key => {
let value = obj[key];
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend();
return value;
},
set(newVal) {
value = newVal;
dep.notify();
}
});
});
}
实际应用场景
-
组件渲染
每个组件实例对应一个Watcher,在渲染过程中访问的响应式数据会自动收集该Watcher作为依赖。 -
计算属性
计算属性本质是特殊的Watcher,在其计算过程中访问的响应式数据会建立依赖关系。 -
监听器(watch)
通过Watcher监听特定数据的变化,触发回调函数。
注意事项
-
嵌套依赖
Vue 通过Watcher栈管理嵌套依赖场景(如组件嵌套时),确保依赖关系正确。 -
数组处理
对于数组类型,Vue 会劫持push、pop等方法,并额外维护一个Dep实例。 -
Proxy 替代方案
Vue 3 使用Proxy实现更完善的依赖收集,无需显式定义getter/setter。
通过这种设计,Vue 实现了精确的按需更新,避免不必要的重新渲染。







