Vue数据绑定简析小结(4)

getter 且不存在 setter 的情况下,不会获取 key 的数据对象,此时 valundefined ,之后调用 observe 时将不对其进行深度观察。正如之后的 setter 访问器中的:

if (getter && !setter) return

此时数据将是只读状态,既然是只读状态,则不存在数据修改问题,继而无须深度观察数据以便在数据变化时调用观察者注册的方法。

Observe

defineReactive 里,我们先获取了 target[key]descriptor ,并缓存了对应的 gettersetter ,之后根据判断选择是否获取 target[key] 对应的 val ,接着是

let childOb = !shallow && observe(val)

根据 shallow 标志来确定是否调用 observe ,我们来看下 observe 函数:

// src/core/observer/index.js
export function observe (value, asRootData) {
 if (!isObject(value) || value instanceof VNode) {
  return
 }
 let ob
 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
}

首先判断需要观察的数据是否为对象以便通过 Object.defineProperty 定义 __ob__ 属性,同时需要 value 不属于 VNode 的实例( VNode 实例通过 Diff 补丁算法来实现实例对比并更新)。接着判断 value 是否已有 __ob__ ,如果没有则进行后续判断:

  • shouldObserve:全局开关标志,通过toggleObserving来修改。
  • !isServerRendering():判断是否服务端渲染。
  • (Array.isArray(value) || isPlainObject(value)):数组和纯对象时才允许添加__ob__进行观察。
  • Object.isExtensible(value):判断value是否可扩展。
  • !value._isVue:避免Vue实例被观察

满足以上五个条件时,才会调用 ob = new Observer(value) ,接下来我们要看下 Observer 类里做了哪些工作

// src/core/observer/index.js
export class Observer {
 constructor (value) {
  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)
  }
 }

 /**
  * Walk through all properties and convert them into
  * getter/setters. This method should only be called when
  * value type is Object.
  */
 walk (obj) {
  const keys = Object.keys(obj)
  for (let i = 0; i < keys.length; i++) {
   defineReactive(obj, keys[i])
  }
 }

 /**
  * Observe a list of Array items.
  */
 observeArray (items) {
  for (let i = 0, l = items.length; i < l; i++) {
   observe(items[i])
  }
 }
}
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/385.html