主题
observe 观察者
提示
observe
是响应式处理的入口,如果一个对象value
没有被观察过,则创建一个观察者实例:ob = new Observer(value)
来对数据进行观察,observe
函数最终返回一个被观察对象的实例。
observe
函数源码如下
js
export function observe( value: any, shallow?: boolean, ssrMockReactivity?: boolean ): Observer | void {
// 1. 若是被观察过的, 则将__ob__返回, 不用继续观察
// 被观察过的对象身上都会有一个__ob__属性
if (value && hasOwn(value, "__ob__") && value.__ob__ instanceof Observer) {
return value.__ob__;
}
if (
shouldObserve &&
(ssrMockReactivity || !isServerRendering()) &&
(isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value.__v_skip /* ReactiveFlags.SKIP */ &&
!isRef(value) &&
!(value instanceof VNode)
) {
// 没有被观察过, 会创建一个观察者实例 ob 来对其进行观察
return new Observer(value, shallow, ssrMockReactivity);
}
}
最后 ob && ob.vmCount++
, 根$data 身上的观察者实例数量会加 1
分析到这里, 就需要分析一下Observer
观察者了
Observer 观察者类
Observer
是一个类,它的作用是给对象的属性添加 getter
和 setter
,用于依赖收集和派发更新:
ts
export class Observer {
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor(public value: any, public shallow = false, public mock = false) {
// this.value = value // v2.7.14版本被 注释了
this.dep = mock ? mockDep : new Dep();
this.vmCount = 0;
def(value, "__ob__", this); // 设置 value.__ob__ = ob, 将实例挂载原始对象的__ob__上
if (isArray(value)) {
if (!mock) {
if (hasProto) {
(value as any).__proto__ = arrayMethods;
} else {
for (let i = 0, l = arrayKeys.length; i < l; i++) {
const key = arrayKeys[i];
def(value, key, arrayMethods[key]);
}
}
}
if (!shallow) {
this.observeArray(value); // 数组则递归observe
}
} else {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
// 对象则 对每一个key执行defineReactive, 将每一个key都变成响应式
defineReactive(value, key, NO_INITIAL_VALUE, undefined, shallow, mock);
}
}
}
/**
* Observe a list of Array items.
*/
observeArray(value: any[]) {
for (let i = 0, l = value.length; i < l; i++) {
observe(value[i], false, this.mock);
}
}
}
可以看到, Observer
的构造函数中, 首先会给被观察对象加上一个__ob__
属性, 值为观察者(Observer
)实例对象
接着区是否为数组, 数组则遍历数组每一项, 递归进行observe
, 见observeArray
方法
不是数组则用for...in
遍历每一个属性, 对每一个属性进行defineReactive
处理, 这里需要注意一个细节调用defineReactive
时候的第三个参数 NO_INITIAL_VALUE
;NO_INITIAL_VALUE
的定义为const NO_INITIAL_VALUE = {}
, 在Observer
中调用defineReactive
的时候, val
传入的并非是对象中每一项的真实值obj[k]
, 而是 "一个空对象"; 为什么要这么做?
这时候就应该分析defineReactive
方法具体逻辑了