面試時vue響應式原理這麼說,全面而有條理

簡單來說:

vue實現響應式(雙向綁定)主要做了3件事,一是用劫持數據或者代理數據來監聽數據變化;二是收集依賴,也就是確定Dom依賴了哪些數據;三是使用了發佈訂閱模式去實現,當數據變化時自動通知需要更新的視圖部分,並進行更新。

具體來說:

vue2利用了js的Object.defineProperty方法去做數據劫持,採用發佈/訂閱者模式實現了數據變化消息的傳遞,兩者結合起來實現了雙向綁定。當我們使用vue構造函數創建一個vue實例時,會傳入一個dom、一個data,也就是視圖和數據。此時vue構造函數內部做了兩件事:

vue構造函數做的第一件事是:

遞歸遍歷data數據對象裏的所有屬性,爲每個屬性運用上Object.defineProperty方法,去設置getter和setter,達到劫持的目的。接着就是在get和set裏做文章了。在getter中收集依賴,在setter中觸發依賴。先收集依賴,就是把用到該數據的地方收集存儲起來,然後等屬性發生變化時,把之前收集好的依賴循環觸發一遍就行了。
1、在屬性的getter方法裏,進行依賴收集。getter爲該屬性創建一個發佈者對象Dep,以及一個訂閱者對象watcher列表(vue用數組來管理),來管理當前這個屬性的所有訂閱者。所以可以說data中每個屬性都擁有一個發佈者對象。
2、在屬性的setter方法裏很簡單,每個setter就是一個觀察者。如果該屬性被重新賦值了,就通知這個屬性的所有訂閱者,也就是發佈消息,由訂閱者對象去通知視圖更新。

vue構造函數做的第二件事是:

解析模板指令Compile,也是遞歸的方式遍歷所有節點,遍歷過程中,會爲那些用雙花括號{{}}和bind指令、on綁定了data變量的節點,創建一個個訂閱者對象watcher,讀取這個變量值的時候,就觸發了getter就把這個訂閱者添加到之前創建的訂閱者對象列表中。並且定義視圖更新函數(如果是text節點,就改變node.textContent,如果是Element節點就改變node.value),在setter方法觸發時就執行視圖更新函數,更新DOM。

接着說vue2做數據劫持的缺陷

1、響應化過程需要一次遍歷data、props,消耗較大;
2、不支持數組、Set/Map、weakSet/weakMap、Class等類型;
3、新增或刪除屬性無法監聽;
4、數組響應化需要額外實現,數組額外重寫7個方法(數組變異);
5、對應的修改語法有限制,增加心智負擔;($set、$delete這些)

最後說vue3做數據劫持的方法

vue3採用ES6的Proxy api實現數據劫持。Proxy的代理是針對整個對象的,而不是對象的某個屬性,因此不同於Object.defineProperty必須遍歷對象每個屬性,Proxy只需要做一層代理就可以監聽同級結構下的所有屬性變化,當然對於深層結構,遞歸還是需要進行的。Vue3 就用一個Proxy就能解決上面所有的問題,尤雨溪本人說由於不需要遍歷,響應化過程能提升100%,內存佔用減少50%。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章