讀這篇文章前,最好是先讀vue數據綁定源碼,由於本篇是接這章寫的,放在一篇文章裏,篇幅太大,我只好分紅兩章了。vue
Vue.prototype._init = function (options) { initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) // 初始化數據的入口 initProvide(vm) // resolve provide after data/props callHook(vm, 'created') if (vm.$options.el) { vm.$mount(vm.$options.el) // 掛載組件 } } // mountComponent是在掛載組件時調用的方法 export function mountComponent (vm, el ,hydrating) { callHook(vm, 'beforeMount') let updateComponent = () => { vm._update(vm._render(), hydrating) } new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */) if (vm.$vnode == null) { vm._isMounted = true callHook(vm, 'mounted') } return vm }
上一篇文章,咱們已經瞭解了Observer
、Dep
、Watcher
都是負責什麼?如何互相協做?
接下來,咱們從數據的入口開始,瞭解vue是如何使用這幾個類完成的數據驅動視圖更新的?
初始化state,就是初始化這幾個屬性。node
先講下什麼是可觀察者對象呢?
具有兩個條件:
一、取值的時候,能把要取值的watcher
(觀察者對象)加入它的dep
(依賴,也可叫觀察者管理器)管理的subs
列表裏(即觀察者列表);
二、設置值的時候,有了變化,全部依賴於它的對象(即它的dep
裏收集到的觀察者watcher
)都獲得通知。watcher
裏面存儲它都觀察了誰(dep
),dep
裏面存儲了都誰觀察了本身。segmentfault
循環每一個props
屬性,對每一個屬性調用defineReactive
,把每一個屬性加上get
和set
裝飾器,變爲可觀察者對象,若是屬性值是對象也會遞歸轉化。數組
observe
就是循環把data
中的全部項都轉換成可觀察者對象,若是子項是對象或數組就遞歸轉化,確保data
裏的每一項及其後代都轉化成了可觀察者對象
初始化數據時,無論data裏的數據渲染用沒用到,都會轉成可觀察者對象。
對於props
和data
,只有哪一個watcher
用到了去讀取時,纔會把該watcher
加到他的觀察者列表中。ide
data
和props
裏都調用了proxy
這個方法,他是作什麼的呢?proxy(vm,’_data’,key)
proxy
就是把data
和props
下的屬性都代理到了vm實例下,vm._data.a
等價於vm.a
原理就是Object.defineProperty
給vm
的key
屬性設置get
和set
方法,當訪問get
的時候,返回的是vm._data[key]
;當訪問set
的時候,設置的是vm._data[key]
的值。oop
初始化計算屬性,就是爲每個計算屬性定義一個Watcher
觀察者對象。這個對象是lazy
的,不會當即就去執行計算(即get方法),等到用的時候纔會去計算,這個時候就會去讀取這個計算屬性依賴的可觀察屬性的值來計算,讀取的時候就會把這些依賴添加進這個計算watcher
裏,同時這些依賴的訂閱者列表也會加入這個計算watcher
。因此當依賴變化時,通知到他的全部訂閱watcher
。計算watcher
接到依賴發生變化了,不會當即計算新值,而是標記dirty
爲true
,讀取這個計算屬性的時候,發現dirty
爲true
,就是說數據已經不是最新的了,須要從新計算,而後纔去計算,不然直接取上一次計算的值value
。spa
若是某個data
經過計算屬性間接的被用到了渲染裏,那麼這個data
也會被加入到渲染watcher
的依賴列表,它的訂閱者列表也會保存渲染watcher
。
只有當模版裏使用了該計算屬性,這個計算屬性依賴的可觀察者纔會被加入到渲染watcher
的依賴列表。若是模版裏沒有直接或間接用到可觀察者對象屬性,那麼當你set
它的時候,也就不會觸發更新操做。prototype
初始化watch
,就是爲每一個watch
屬性建立一個觀察者對象,這個expOrFn
解析取值表達式去取值,而後就會調用相關data/prop
屬性的get
方法,get
方法又會在他的觀察者列表里加上該watcher
,一旦這些依賴屬性值變化就會通知該watcher
執行update
方法。即會執行他的回調方法cb
,也就是watch
屬性的handler
方法。代理
到這裏,數據的初始化就完成了。code
這個方法是在,全部的數據初始化完成後,執行掛載組件時調用,建立一個渲染watcher
,每一個組件有且僅有一個渲染watcher
。updateComponent
是watcher
的getter
屬性,建立後,當即調用get
方法,便是調用updateComponent
,也就是調用render
方法,render
裏使用了的數據就會讀取相關的data
的get
方法,就會把data
的依賴加進這個渲染watcher
的依賴列表裏,data
的subs
也會加入渲染watcher
,如此,當設置data
時攔截的set
方法就會通知渲染watcher
調用update
方法。
我總結下:
一個數據變動後,通知他的Watcher去執行update。
不一樣類型的Watcher職責不一樣,vue裏的Watcher能夠分爲3類:
渲染Watcher、計算Watcher、偵聽器Watcher,注意這3中Watcher的getter屬性分別是什麼。