天天看點

Vue源碼:資料響應式原理

目的

徹底弄懂Vue2 的資料更新原理,手寫相關實作代碼,讓相關知識不再處于“忽悠階段”

Vue源碼:資料響應式原理

從MVVM模式說開去

Vue源碼:資料響應式原理

侵入式和非侵入式

Vue源碼:資料響應式原理

上帝的鑰匙

Object.defineProperty()

資料劫持 / 資料代理

利用JavaScript引擎賦予的功能,檢測對象屬性變化

僅有"上帝的鑰匙"不夠,還需要設計一套精密的系統

Object.defineProperty()方法

Object.defineProperty()方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,并傳回此對象。

Object.defineProperty()方法接收三個參數,第一個參數是定義哪一個對象,第二個參數是定義什麼屬性,第三個參數是屬性值。

Object.defineProperty()方法可以設定一些額外隐藏的屬性

writeable可以定義屬性是否可以寫

enumerable可以定義屬性是否可以被枚舉,指的是在調用for in…方法的時候是否會被枚舉

getter / setter

屬性的getter函數,如果沒有getter,則為<code>undefined</code>。當通路該屬性時,會調用此函數。執行時不傳入任何參數,但是會傳入<code>this</code>對象(由于繼承關系,這裡的<code>this</code>并不一定是定義該屬性的對象)。該函數的傳回值會被用作屬性的值。

預設為<code>undefined</code>。

屬性的setter函數,如果沒有setter,則為<code>undefined</code>。當屬性值被修改時,會調用此函數。該方法接受一個參數(也就是被賦予的新值),會傳入指派時的<code>this</code>對象。

這裡有一個小坑:用閉包存儲get 和set 的值

Vue源碼:資料響應式原理

defineReactive函數

getter / setter需要變量周轉才能工作

Vue源碼:資料響應式原理

使用defineReactive函數不需要設定臨時變量,而是用閉包

Vue源碼:資料響應式原理

遞歸偵測對象全部屬性

Vue源碼:資料響應式原理

數組的響應式處理

改寫七個方法,以Array.prototype為原型,建立了一個arrayMethods對象,并且用es6的Object.setPrototypeOf方法,讓數組的__proto__指向了arrayMethods,就可以調用新定義的七個函數方法。

Vue源碼:資料響應式原理

依賴收集

需要用到資料的地方,稱為依賴

Vue1.x,細粒度依賴,用到資料的DOM都是依賴

Vue2.x,中等粒度依賴,用到數組的元件是依賴

在getter中收集依賴,在setter中觸發依賴

把依賴收集的代碼封裝成一個Dep 類,它專門用來管理依賴,每個Observer 的執行個體,成員中都有一個Dep 的執行個體;

Watcher 是一個中介,資料發生變化時通過Watcher 中轉,通知元件

依賴就是Watcher 。隻有Watch觸發的getter才會收集依賴,哪個

Watcher 觸發了getter,就把哪個Watch收集到Dep中。

Dep 使用釋出訂閱模式,當資料發生變化時,會循環依賴清單,把所

有的Watcher 都通知一遍。

代碼實作的巧妙之處:Watcher把自己設定到全局的一個指定位置,然後讀取資料,因為讀取了資料,是以會觸發這個資料的getter。在getter 中就能得到目前正在讀取資料的Watcher,并把這個Watcher 收集到Dep 中。

Vue源碼:資料響應式原理

完整代碼

Vue源碼:資料響應式原理