export class Observer {
value: any;
dep: Dep;
vmCount: number; // 具有该对象作为根$data的vm的数量
constructor (value: any) {
this.value = value
this.dep = new Dep() // 用来存放array的依赖
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)
}
}
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
概述:
对于Observer类,这个类,就是给每一个对象,添加一个 __ob__
属性,并且把这个对象,变成getter/setter形式。变成这样的形式呢,会方便收集依赖,并且在数据发生变化的时候,通知各个依赖。
相关方法
-
Dep
类里面使用this.dep = new Dep()
,是为了存放数组的依赖,因为数组在getter的时候收集依赖,在拦截器里触发依赖,将数组的依赖放在Observer的实例上,是为了让数组的getter和拦截器中都能访问到。 -
def()
这个方法,是用来处理value,给它添加一个__ob__
的属性,这个属性的值就是当前Observer的实例,因为数组的依赖保存在Observer的实例上,所以添加这个值,就可以在拦截器中访问Observer实例,并拿到相应的依赖。
function def (obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
// Observer 类中
def(value, '__ob__', this)
- 判断value是对象还是数组,如果是对象的话,就走walk方法,walk方法就是把object自身有的属性遍历一边,然后用
defineReactive()
方法全部转换成getter/setter形式 - 如果是数组对象,就需要先判断一下,浏览器能不能支持
__proto__
这个属性,为什么要判断这个属性?因为数组的某些原型中的方法,需要覆盖,通过判断hasProto
来用两种方法来处理覆盖value原型的功能,支持__proto__
,使用protoAugment()
函数覆盖原型,如果不支持,则调用copyAugment()
函数将拦截器中的方法挂载到vulue上。
function protoAugment (target, src: Object) {
target.__proto__ = src
}
function copyAugment (target: Object, src: Object, keys: Array<string>) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
def(target, key, src[key])
}
}
observeArray()
方法
循环Array中的每一项,执行observe函数来侦测变化,通过observe函数,将数组中的每一个元素都执行一遍new Observer()
。observe()
export function observe (value: any, asRootData: ?boolean): Observer | void {
// 不是对象或者不是VNode的实例,就返回
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
// 有observer实例就返回该实例
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value)
}
if (asRootData && ob) {
ob.vmCount++
}
// 否则返回新增的实例
return ob
}