這就要從reactive開始講起了,粗略的說,js的操做能引發頁面上顯示的改變,是由於該操做引發了組件的從新渲染,渲染會生成新的虛擬節點,新節點和舊節點會對比,操做瀏覽器的node進行改變。vue
vue實例如下簡稱vmnode
說具體點react
data()方法的返回值以及watch,props,computed裏面的屬性,,在這以前都會被defineReactive方法重寫get和set方法(get方法重寫爲調用的時候收集Dep這個靜態變量指向的watcher,set方法調用的時候會notify收集的watchers,調用每一個watcher的update--->run--->get方法)和methods裏面的方法一塊兒,被掛載到vm實例上(因此methods裏面this.XXX纔有用,由於調用method的是 vm,屬性也在vm上)數組
-----------------因此若是想要對象(好比a)的屬性b的set方法能引發從新渲染,必須在b被get的時候,收集到能夠引發從新渲染的watcher。那麼是何時收集的呢?瀏覽器
每個vm有一個render Watcher,在mountComponent的時候生成,render Watcher的expOrFn方法是 vm._update(vm._render(), hydrating)--->vm.__patch__(prevVnode, vnode),(對比新舊虛擬節點,操做真實node),在這個過程當中,vm._render()會按照Vue的<template>中的內容,爲每個子節點this
生成屬性,查看render的代碼會發現有個with(this),這裏this就是vm,就是要調用vm的屬性的get方法給虛擬節點的屬性賦值。而後再進行對比等操做。在這個過程當中,被調用get方法的屬性就會收集renderWatcher。server
-----------------那爲何array[0]='a'這樣的方法不會從新渲染?對象
由於array的0這個屬性?,沒有重寫get和set方法遞歸
-----------------爲何pop push能夠reactive?get
好比a.b=c,reactive的過程是: observe(a)---> defineReactive(b)--->重寫b的get方法以前先observe(c)。observe c的時候,若是判斷c是一個數組,那麼c的pop.、push等方法會從新指向,指向後的新方法,先調用Array原來來對應的方法,而後調用_ob_指向的observer的dep的notify方法,通知收集的watcher
-----------------對象的dep從哪裏來?
上面說過,observe(c),new一個Observer 實例childOb,c的_ob_屬性指向childOb,childOb裏面有一個dep屬性,而在b的重寫的get方法中,會有childOb.dep.depend()的執行
-----------------靈魂第五問:既然是給b重寫set和get的時候,給c的_ob_的dep收集Watcher,那麼數組裏面的元素好比array[0]=d,而d剛好是數組,爲何d.push也能夠reactive?
在childOb.dep.depend()方法下面還有個if,若是屬性指向的是個數組,直接遞歸收集。那麼這時候若是是數組的元素是個對象,就無論了,只考慮數組 中的元素仍是數組的狀況。因此array[0]='a'是不能reactive的,可是array[0].push('a')是能夠reactive的