浅析Vue相应式道理(三)

Vue相应式道理之defineReactive

defineReactive

不论如何,终究相应式数据都要经由过程defineReactive来完成,现实要借助ES5新增的Object.defineProperty

defineReactive接收五个参数。obj是要增加相应式数据的对象;key是属性名,val是属性名对应的取值;customSetter是用户自定义的setter;会在相应式数据的setter中实行,只要开辟环境可用;经由过程shallow指定是不是浅比较,默许深比较。

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  const dep = new Dep()

  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  const getter = property && property.get
  if (!getter && arguments.length === 2) {
    val = obj[key]
  }
  const setter = property && property.set

  let childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      /* eslint-disable no-self-compare */
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      /* eslint-enable no-self-compare */
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    }
  })
}

在函数内,起首实例化一个Dep实例depdep会在稍后增加为相应式数据自定义的get/set中发挥作用。接着猎取属性描述符,假如属性不可设置,则没法挪用Object.defineProperty来修正setter/getter,所以返回。

假如本来已设置过setter/getter,缓存起来。当未自定义getter且arguments长度为2(即只传入了objkey)时,能够直接用方括号求值,运用闭包变量val缓存初始值。

假如不是浅复制,实行observe(val),为val增加__ob__属性并返回__ob__指向的Observer实例。(只要数组和对象才多是相应式,才返回Observer实例)。

运用Object.definePropertyobj[key]设置getter和setter。

get内,假如本来已设置过getter,则用缓存的getter求值,不然运用闭包变量val作为返回值;同时增加依靠。此处为两个Dep实例增加依靠。dep是闭包变量,在getter/setter中会运用到。另一个Dep实例是childOb.dep,只用挪用set/delete更新相应式数据时,才会触发;假如value是数组,还会遍历元素,为存在__ob__属性的元素网络依靠。

set内,先猎取更新前的值(逻辑和get内第一步一样)。推断更新前后的值是不是相称,相称时直接返回;不等时,假如有缓存的setter,挪用缓存的setter更新,不然直接赋值。值得注意的是,NaN === NaN是不建立的,反而NaN !== NaN是建立的,背面的推断语句newVal !== newVal && value !== value就是为了防止newVal/val都是NaN。在更新后的值newVal上实行observe,更新闭包变量childOb,并挪用notify。

参考链接

    原文作者:荡漾
    原文地址: https://segmentfault.com/a/1190000017216175
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞