Skip to content

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 是一个类,它的作用是给对象的属性添加 gettersetter,用于依赖收集和派发更新:

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方法具体逻辑了