vue依赖收集实现
Vue 依赖收集实现原理
Vue 的依赖收集是通过响应式系统的核心机制实现的,主要涉及 Observer、Dep 和 Watcher 三个关键类。
Observer 类
Observer 类负责将对象的属性转换为响应式属性。它通过 Object.defineProperty 或 Proxy(Vue 3)拦截属性的读取和修改操作。

class Observer {
constructor(value) {
this.value = value
this.dep = new Dep()
if (Array.isArray(value)) {
// 处理数组
} else {
this.walk(value)
}
}
walk(obj) {
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
}
Dep 类
Dep 是依赖的管理者,每个响应式属性都有一个对应的 Dep 实例。它负责收集依赖(Watcher)并在属性变化时通知这些依赖。

class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
notify() {
this.subs.forEach(sub => sub.update())
}
depend() {
if (Dep.target) {
Dep.target.addDep(this)
}
}
}
Watcher 类
Watcher 是依赖的具体实现,它会在初始化时触发属性的 getter,从而将自己添加到 Dep 中。
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm
this.getter = parsePath(expOrFn)
this.cb = cb
this.value = this.get()
}
get() {
Dep.target = this
const value = this.getter.call(this.vm, this.vm)
Dep.target = null
return value
}
addDep(dep) {
dep.addSub(this)
}
update() {
this.run()
}
run() {
const value = this.get()
if (value !== this.value) {
const oldValue = this.value
this.value = value
this.cb.call(this.vm, value, oldValue)
}
}
}
依赖收集流程
- 初始化组件时,会为每个响应式属性创建一个 Observer 实例。
- 当属性被访问时(getter 触发),会调用
dep.depend()将当前 Watcher(Dep.target)添加到 Dep 的订阅列表中。 - 当属性被修改时(setter 触发),会调用
dep.notify()通知所有订阅的 Watcher 进行更新。
示例代码
function defineReactive(obj, key, val) {
const dep = new Dep()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
if (Dep.target) {
dep.depend()
}
return val
},
set: function reactiveSetter(newVal) {
if (newVal === val) return
val = newVal
dep.notify()
}
})
}
Vue 3 的改进
Vue 3 使用 Proxy 替代 Object.defineProperty,依赖收集的实现更加高效:
- 不需要递归遍历对象的所有属性。
- 可以监听动态添加的属性。
- 对数组的操作无需特殊处理。
function reactive(obj) {
return new Proxy(obj, {
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
}
})
}






