數(shù)據(jù)綁定

數(shù)據(jù)綁定模塊 最核心的三個(gè)類: Observer,Watcher,Dep

observer是Vue核心中最重要的一個(gè)模塊(個(gè)人認(rèn)為),能夠?qū)崿F(xiàn)視圖與數(shù)據(jù)的響應(yīng)式更新,底層全憑observer的支持。

observer模塊在Vue項(xiàng)目中的代碼位置是src/core/observer,模塊共分為這幾個(gè)部分:

  • Observer: 數(shù)據(jù)的觀察者,讓數(shù)據(jù)對(duì)象的讀寫操作都處于自己的監(jiān)管之下
  • Watcher: 數(shù)據(jù)的訂閱者,數(shù)據(jù)的變化會(huì)通知到Watcher,然后由Watcher進(jìn)行相應(yīng)的操作,例如更新視圖
  • Dep: Observer與Watcher的紐帶,當(dāng)數(shù)據(jù)變化時(shí),會(huì)被Observer觀察到,然后由Dep通知到Watcher

示意圖如下:

Observer

Observer類定義在src/core/observer/index.js中,先來看一下Observer的構(gòu)造函數(shù)

constructor (value: any) {
  this.value = value
  this.dep = new Dep()
  this.vmCount = 0
  def(value, '__ob__', this)
  if (Array.isArray(value)) {
      const augment = hasProto
      ? protoAugment
      : copyAugment
    augment(value, arrayMethods, arrayKeys)
    this.observeArray(value)
  } else {
    this.walk(value)
  }
}

value是需要被觀察的數(shù)據(jù)對(duì)象,在構(gòu)造函數(shù)中,會(huì)給value增加ob屬性,作為數(shù)據(jù)已經(jīng)被Observer觀察的標(biāo)志。如果value是數(shù)組,就使用observeArray遍歷value,對(duì)value中每一個(gè)元素調(diào)用observe分別進(jìn)行觀察。如果value是對(duì)象,則使用walk遍歷value上每個(gè)key,對(duì)每個(gè)key調(diào)用defineReactive來獲得該key的set/get控制權(quán)。

解釋下上面用到的幾個(gè)函數(shù)的功能:

  • observeArray: 遍歷數(shù)組,對(duì)數(shù)組的每個(gè)元素調(diào)用observe
  • observe: 檢查對(duì)象上是否有ob屬性,如果存在,則表明該對(duì)象已經(jīng)處于Observer的觀察中,如果不存在,則new Observer來觀察對(duì)象(其實(shí)還有一些判斷邏輯,為了便于理解就不贅述了)
  • walk: 遍歷對(duì)象的每個(gè)key,對(duì)對(duì)象上每個(gè)key的數(shù)據(jù)調(diào)用defineReactive
  • defineReactive: 通過Object.defineProperty設(shè)置對(duì)象的key屬性,使得能夠捕獲到該屬性值的set/get動(dòng)作。一般是由Watcher的實(shí)例對(duì)象進(jìn)行g(shù)et操作,此時(shí)Watcher的實(shí)例對(duì)象將被自動(dòng)添加到Dep實(shí)例的依賴數(shù)組中,在外部操作觸發(fā)了set時(shí),將通過Dep實(shí)例的notify來通知所有依賴的watcher進(jìn)行更新。
    如果不太理解上面的文字描述可以看一下圖:

Dep

Dep是Observer與Watcher之間的紐帶,也可以認(rèn)為Dep是服務(wù)于Observer的訂閱系統(tǒng)。Watcher訂閱某個(gè)Observer的Dep,當(dāng)Observer觀察的數(shù)據(jù)發(fā)生變化時(shí),通過Dep通知各個(gè)已經(jīng)訂閱的Watcher。

Dep提供了幾個(gè)接口:

  • addSub: 接收的參數(shù)為Watcher實(shí)例,并把Watcher實(shí)例存入記錄依賴的數(shù)組中
  • removeSub: 與addSub對(duì)應(yīng),作用是將Watcher實(shí)例從記錄依賴的數(shù)組中移除
  • depend: Dep.target上存放這當(dāng)前需要操作的Watcher實(shí)例,調(diào)用depend會(huì)調(diào)用該Watcher實(shí)例的addDep方法,addDep的功能可以看下面對(duì)Watcher的介紹
  • notify: 通知依賴數(shù)組中所有的watcher進(jìn)行更新操作

Watcher

Watcher是用來訂閱數(shù)據(jù)的變化的并執(zhí)行相應(yīng)操作(例如更新視圖)的。Watcher的構(gòu)造器函數(shù)定義如下:

constructor (vm, expOrFn, cb, options) {
  this.vm = vm
  vm._watchers.push(this)
  // options
  if (options) {
    this.deep = !!options.deep
    this.user = !!options.user
    this.lazy = !!options.lazy
    this.sync = !!options.sync
  } else {
    this.deep = this.user = this.lazy = this.sync = false
  }
  this.cb = cb
  this.id = ++uid // uid for batching
  this.active = true
  this.dirty = this.lazy // for lazy watchers
  this.deps = []
  this.newDeps = []
  this.depIds = new Set()
  this.newDepIds = new Set()
  this.expression = process.env.NODE_ENV !== 'production'
    ? expOrFn.toString()
    : ''
  if (typeof expOrFn === 'function') {
    this.getter = expOrFn
  } else {
    this.getter = parsePath(expOrFn)
    if (!this.getter) {
      this.getter = function () {}
      process.env.NODE_ENV !== 'production' && warn(
        `Failed watching path: "${expOrFn}" ` +
        'Watcher only accepts simple dot-delimited paths. ' +
        'For full control, use a function instead.',
        vm
      )
    }
  }
  this.value = this.lazy
    ? undefined
    : this.get()
}

參數(shù)中,vm表示組件實(shí)例,expOrFn表示要訂閱的數(shù)據(jù)字段(字符串表示,例如a.b.c)或是一個(gè)要執(zhí)行的函數(shù),cb表示watcher運(yùn)行后的回調(diào)函數(shù),options是選項(xiàng)對(duì)象,包含deep、user、lazy等配置。

watcher實(shí)例上有這些方法:

  • get: 將Dep.target設(shè)置為當(dāng)前watcher實(shí)例,在內(nèi)部調(diào)用this.getter,如果此時(shí)某個(gè)被Observer觀察的數(shù)據(jù)對(duì)象被取值了,那么當(dāng)前watcher實(shí)例將會(huì)自動(dòng)訂閱數(shù)據(jù)對(duì)象的Dep實(shí)例
  • addDep: 接收參數(shù)dep(Dep實(shí)例),讓當(dāng)前watcher訂閱dep
  • cleanupDeps: 清除newDepIds和newDep上記錄的對(duì)dep的訂閱信息
  • update: 立刻運(yùn)行watcher或者將watcher加入隊(duì)列中等待統(tǒng)一flush
  • run: 運(yùn)行watcher,調(diào)用this.get()求值,然后觸發(fā)回調(diào)
  • evaluate: 調(diào)用this.get()求值
  • depend: 遍歷this.deps,讓當(dāng)前watcher實(shí)例訂閱所有dep
  • teardown: 去除當(dāng)前watcher實(shí)例所有的訂閱

observe(value):

function observe (value, asRootData) {
  if (!isObject(value)) {
    return
  }
  var ob;
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__;
  } else if (
    observerState.shouldConvert &&
    !isServerRendering() &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    ob = new Observer(value);
  }
  if (asRootData && ob) {
    ob.vmCount++;
  }
  return ob
}

給 value 定義一個(gè) __ob__ 作為 Observer 的 key

value:
    __ob__:Observer
    key1:
        get: function reactiveGetter () {
              var 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) {
          var 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 = observe(newVal);
          dep.notify();
        }


__ob__:
    value: value
    dep: dep

轉(zhuǎn)載自:https://segmentfault.com/a/1190000008377887

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容