/** * Observer 类会附加到每一个被侦测的Object上 * 一旦被附加上,Observer会将Object的所有属性都转换 * 为getter/setter的形式来手机属性的以来 * 并且当属性变化时会通知这些依赖 */
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
    /** * 给每一个值的原型上新增一个‘__ob__‘属性 * ‘__ob__‘属性的值就是当前Observer的实例 * 通过这个属性就可以拿到数组的依赖了 */
    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方法会将每一个属性都转换成getter/setter * 的形式来侦测变化,这个方法只在数据类型时 * Object的时候被调用 */
  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形式。变成这样的形式呢,会方便收集依赖,并且在数据发生变化的时候,通知各个依赖。

相关方法

  1. Dep
    类里面使用this.dep = new Dep(),是为了存放数组的依赖,因为数组在getter的时候收集依赖,在拦截器里触发依赖,将数组的依赖放在Observer的实例上,是为了让数组的getter和拦截器中都能访问到。

  2. 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) 
  1. 判断value是对象还是数组,如果是对象的话,就走walk方法,walk方法就是把object自身有的属性遍历一边,然后用defineReactive()方法全部转换成getter/setter形式
  2. 如果是数组对象,就需要先判断一下,浏览器能不能支持__proto__这个属性,为什么要判断这个属性?因为数组的某些原型中的方法,需要覆盖,通过判断hasProto来用两种方法来处理覆盖value原型的功能,支持__proto__,使用protoAugment()函数覆盖原型,如果不支持,则调用copyAugment()函数将拦截器中的方法挂载到vulue上。
/** * 使用__proto__截取原型链来增强目标对象或数组 */
function protoAugment (target, src: Object) {
  /* eslint-disable no-proto */
  target.__proto__ = src
  /* eslint-enable no-proto */
}
/** * 通过定义一个隐藏属性来增强目标对象或数组 */
/* istanbul ignore next */
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])
  }
}
  1. observeArray()方法
    循环Array中的每一项,执行observe函数来侦测变化,通过observe函数,将数组中的每一个元素都执行一遍new Observer()
  2. observe()
/** * 尝试为value创建一个Observer的实例。 * 如果创建成功,直接返回新创建的Observer实例 * 如果value已经存在一个Observer实例,就直接返回它 */
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
}

本文地址:https://blog.csdn.net/u014627807/article/details/107155470