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

從MVVM模式說開去
侵入式和非侵入式
上帝的鑰匙
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 的值
defineReactive函數
getter / setter需要變量周轉才能工作
使用defineReactive函數不需要設定臨時變量,而是用閉包
遞歸偵測對象全部屬性
數組的響應式處理
改寫七個方法,以Array.prototype為原型,建立了一個arrayMethods對象,并且用es6的Object.setPrototypeOf方法,讓數組的__proto__指向了arrayMethods,就可以調用新定義的七個函數方法。
依賴收集
需要用到資料的地方,稱為依賴
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 中。
完整代碼