前言
结合上文发布订阅模式,理解Vue的响应式设计
Object.defineProperty
Vue官网经典图
看着感觉就是观察者模式,Data变动时就通知观察者更新,不就是利用Object.defineProperty来改造数据的读写,在它被改变的时候通知所有watcher从而触发视图更新吗?Dep在哪呢?
源码中的Observer、Dep和Watcher
tips:这里贴的代码是我看完后,自己简化的,类名和变量名都是源码中的
Vue封装了一个defineReactive方法来对数据进行defineProperty改造
function defineReactive (
obj: Object,
key: string,
val: any,
) {
Object.defineProperty(obj, key, {
get: function reactiveGetter () {
//添加依赖
dep.depend()
return value
},
set: function reactiveSetter (newVal) {
//发布
dep.notify()
}
})
}
这里能看出这个defineReactive方法在改造数据的时候,数据get时进行依赖的添加,set时发布,可以看出,dep类似消息中介
class Observer {
value: any;
dep: Dep;
constructor (value: any) {
this.value = value
this.dep = new Dep()
if(Array.isArray(value)){
//遍历出来挨个用Observer去new一下
}else{
//是对象就遍历,挨个进行响应式改造改造
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
}
Observer的作用其实就是改造数据,而Vue让每一个响应式的数据都是被Observer改造过的,那么是不是可以理解为,每一个被Observer new 过的数据就是类似publisher发布者的存在
再看一下Dep类
class Dep {
static target: ?Watcher;
id: number;
subs: Array<Watcher>;
constructor () {
this.id = uid++
this.subs = []
}
addSub (sub: Watcher) {
this.subs.push(sub)
}
removeSub (sub: Watcher) {
remove(this.subs, sub)
}
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify () {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
dep里维护一个watcher列表,并且有depend和notify方法,能添加watcher并且发布通知,印证了这个dep就是消息中介
Watcher类,addDep添加依赖(订阅),并具有update方法
class Watcher {
addDep (dep: Dep) {
const id = dep.id
//添加依赖(像是订阅操作i)
dep.addSub(this)
}
update () {
this.run()
}
run () {
if (this.active) {
//执行数据更新
}
}
总结
每一个数据都会被Observer改造成响应式的,这个响应式的数据就是发布者,每一个数据对应有一个自己的dep
读数据时,触发get,调用dep的depend方法添加所有watcher(订阅,是调用了watcher的addDep方法)
改数据时,触发set,调用dep的notify方法通知所有watcher(订阅者)执行更新。
以上是vue2的原理,vue3待写
参考