一步一步分析vue之observe

wangy7099發表於2019-02-28

上一期,本我們講了__data這個vue的屬性是怎麼一回事,本期,我們將用到vue的(2.5.9)版本,讓我們瞭解一下observe 讓我們看看observe都包含什麼成員

observe = {
    value : "",
    dep : new Dep,
    vmCount : 0
}
複製程式碼

那麼 Dep 又是什麼東西呢。

dep = {
    id : uid++,
    subs : []
}
複製程式碼

好,讓我們回到observe最開始出現的地方。在程式碼的3360行。

1
接著,按f11跟進去,我們可以看到,程式用new Observer(value)初始化了value,如下圖所示。
2
接著按f11跟進去,我們看看初始化Observer做了些什麼事情?
3
我們可以看到在程式的874行,用def(value, '__ob__', this);,用def對value和__Observer__進行處理。不用說,這肯定不是函式式的了 = =。讓我們繼續跟進去,看看def對value做了什麼事情?按f11跟進去,如下圖所示。
4
可以看到,不出所料,又是用了Object.defineProperty給這個value定義了一個 __ob__ 這個屬性。這個屬性在分析__data章節裡給了個可以查閱的連結。但是,重點的是:我們知道,在程式碼的initData函式裡,data=_data,而__ob__的value又被定義為value,也就是data,所以如果_data的值發生改變,data的值會發生變化,__ob__的值也會發生變化,會相應的觸發getter/setter。呼叫完def這個函式,接下來該呼叫this.walk了,如下圖。
5
this.walk接收的是一個剛剛賦值完__ob__屬性的value屬性。同樣,讓我們跟進去,看看究竟對value做了什麼,如下圖。
6
這裡,obj即使我們剛才所傳的value.可以看到,先用Object.keys取到的obj所有的key,然後用了一個for迴圈,對obj的每個key都呼叫defineReactive(obj, keys[i], obj[keys[i]]);,哈哈,既然它對每個keys[i],obj[keys[i]],都呼叫了這個defineReactive方法,我們不妨跟進去看看~~~。如下圖。
7
哇!引數看著好高大上 = = 有木有 (先寫這些,剩下的等明天再寫。)
繼續, 現在是2017年12月11日20:29:17
defineReactive這個函式的大致意思就是為我們$options裡面的data,也就是說 __data(因為講_data那期已經提過了,有一處程式碼是data = _data)的key定義setter/getter方法。
我們先來看看程式碼的979行,即var childOb = !shallow && observe(val);.這句話適用於當你的data裡key對應的值是物件的情況下,就會遞迴地進行observe了。不知道的童鞋可以執行到此處然後f11進去看看。好,我們來看看他的get/set方法~寫在注視裡了

get

 get: function reactiveGetter () {
      var value = getter ? getter.call(obj) : val;//先看看有沒預設的get方法,沒有就用val,即當初傳進來的值
      if (Dep.target) {//這個以後在分析
        dep.depend();
        if (childOb) {
          childOb.dep.depend();
          if (Array.isArray(value)) {
            dependArray(value);
          }
        }
      }
      return value
    }
複製程式碼

set

set: function reactiveSetter (newVal) {
      var value = getter ? getter.call(obj) : val;//先看看有沒預設的get方法,沒有就用val,即當初傳進來的值
      /* eslint-disable no-self-compare */
      //如果新值等於舊值,就不觸發檢視更新等操作了。
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      /* eslint-enable no-self-compare */
      if ("development" !== 'production' && customSetter) {
        customSetter();
      }
      //如果有預設set方法就用預設的,否則新值賦給舊值。
      if (setter) {
        setter.call(obj, newVal);
      } else {
        val = newVal;
      }
      //重新生成一下childOb 處理 字串變為物件 或者 物件變為字串 等情況。
      childOb = !shallow && observe(newVal);
      //notify 觸發檢視更新操作。
      dep.notify();
    }
複製程式碼

好了,observe分析的差不多了。下一步我們該分析$mount了。

相關文章