我们上次学习了vue数据驱动的概念,以及简单的vue怎么知道数据更新,然后采取行动的。今天我们就来继续深入学习,vue怎么把数据和视图给绑定在一起的,数据发生变化,视图怎么会自动发生变化的。
vue中的Observer
之前讲了vue知道数据发生变化利用了Object.defineProperty
函数,那么对于vue中定义的数据它是怎么把所有的数据给监听到呢。
这里就是Observer类做的事情,他会通过递归的方式把一个对象的所有属性都转化为可观测的对象。
首先Observer是一个类。
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
有它的构造函数,每个要监听的属性值都会有自己的dep, this.dep = new Dep()
也就是收集依赖存放的地方,然后为每个value定义了一个__ob__
属性,它的值就是该Observer实例。这样就是为它打上标记,表示已经转化为响应式了,避免重复操作。
对于数组的响应式需要单独处理if (Array.isArray(value))
,否则就是对象,采用this.walk(value)
进行处理。
我们先看Object的情况walk怎么处理的
walk函数的实现
walk就是遍历完Object的所有的属性,把每个属性都转换成getter/setter的形式来侦测变化。
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
这是walk的实现,就是在遍历Object的每个属性,然后调用defineReactive函数来操作。如果传入的属性值还是一个Object的时候,会使用new Observer(val)来递归。
export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
}
在这段代码中实现的。