先來看看 Vue 的配置,以組件爲例this
{ render(h) { }, props: { props1: Number }, data() { return { data1: 1, data2: 0 } }, computed: { computed1() { return this.data1 + this.props1 } }, watch: { computed1(newValue) { setTimeout(()=>{ console.log(newValue) },0) } } }
響應式實現過程大概能夠分爲三塊:lua
初始化 data、props、computed 時(初始化 render 時還有一些其餘內置屬性),經過 Object.defineProperty
將屬性定義成 get
和 set
,併爲每一個屬性綁定一個 Dep 實例。code
詳見 src/core/instance/state.js
中 initData
和 initProps
。get
能夠把整個 Vue 應用認爲是大大小小的組件堆砌而成。Vue 爲每一個組件都定義了兩塊重要的內容:Watcher 和 Render。it
執行 $mount
時調用 mountComponent
、初始化 watch、computed時、調用實例方法 $watch時,都會給實例化一個 Watcher。而 Watcher 初始化時會進行一次求值(執行實例中的 getter
方法),首先會將當前實例設置爲 Dep 當前目標,而後觸發數據的相關屬性的 get
方法。console
詳見 src/core/instance/state.js
中 initComputed
和 initWatch
。class
Dep
類就是用來關聯數據與組件的 Watcher 的。響應式
// the current target watcher being evaluated. // this is globally unique because there could be only one // watcher being evaluated at any time. Dep.target = null
其實初始化 Watcher 時,經過執行了對應屬性的 get
方法,將Watcher 實例放入數據對應的 Dep 實例的訂閱列表中。而當數據發生變化時,對應屬性執行 set
方法,會通知到對應的 Dep 實例,再通知訂閱列表中的 Watcher。配置
此時,Watcher 將通知組件執行 Render,從新計算出新的 VNode,經過新舊 VNode 的對比,進行視圖更新。方法