H5大咖分享:Vue3為何使用Proxy實現數據監聽
發布時間:
2020-08-13
版權所有:
云和教育
分享:
鄭州h5培訓教程:Vue3為何使用Proxy實現數據監聽前言
vue3響應式數據放棄了Object.define Property,而使用Proxy來代替它。我們知道,在 vue2 中,實現數據監聽是使用Object.defineProperty –> 實現方法可看:vue 數據雙向綁定原理。而這個方法有缺點,并且不能實現數組和對象的部分監聽情況;具體也可以看我之前寫的一篇博客:關于 Vue 不能 watch 數組 和 對象變化的解決方案。最新的 Proxy,相比 vue2 的 Object.define Property,能達到速度加倍、內存減半的成效。具體是怎么實現、以及對比舊的實現方法為啥能有速度加倍、內存減半的特性。
Vue 的初始化過程,分別有Observer 、Compiler 和Watcher。
當我們 new Vue 的時候,會調用Observer ,通過 Object.defineProperty 遍歷 vue 對象的 data、computed 或者 props(如果是組件的話)的所有屬性進行監聽。同時通過Compiler 解析模板指令,解析到屬性后就 new 一個Watcher 并綁定更新函數到 watcher 當中,Observer 和 Compiler 就通過屬性來進行關聯。
如上,當 Observer 中的 setter 檢測到屬性值改變的時候,就調用屬性對應的所有 watcher 調用更新函數,從而更新到屬性對應的 dom。
來個簡單的 Object.defineProperty 例子
Object.defineProperty 需要遍歷所有的屬性,這就造成了如果 vue 對象的 data/computed/props 中的數據規模龐大,那么遍歷起來就會慢很多
同理,如果 vue 對象的 data/computed/props 中的數據規模龐大,那么 Object.defineProperty 需要監聽所有的屬性的變化,那么占用內存就會很大
Proxy 對象用于定義基本操作的自定義行為(如屬性查找,賦值,枚舉,函數調用等)
可以理解為在對象之前設置一個“攔截”,當監聽的對象被訪問的時候,都必須經過這層攔截。可以在這攔截中對原對象處理,返回需要的數據格式。
也就是無論訪問對象的什么屬性,之前定義的 或是新增的 屬性,都會走到攔截中進行處理。這就解決了之前所無法監聽的問題。
const p = new Proxy(target, handler)
target:要使用 Proxy 包裝的目標對象(可以是任何類型的對象,包括原生數組,函數,甚至另一個代理)
handler:一個通常以函數作為屬性的對象,各屬性中的函數分別定義了在執行各種操作時代理 p 的行為
由上可知,新增或編輯屬性,并不需要重新添加響應式處理,都能監聽的到。因為 Proxy 是對對象的操作,只要你訪問對象,就會走到 Proxy 的邏輯中。
Reflect 是一個內置的對象,它提供攔截 JavaScript 操作的方法。這些方法與proxy handlers的方法相同。Reflect不是一個函數對象,因此它是不可構造的
區別
Proxy 和 Object.defineProperty 的使用方法看似很相似,其實 Proxy 是在更高維度 上去攔截屬性的。
Vue2 中,對于給定的 data:如 { count: 1 },是需要根據具體的 key 也就是 count,去對 get 和 set 進行攔截,也就是:
必須預先知道要攔截的 key 是什么,這也就是為什么 Vue2 里對于對象上的新增屬性無能為力,所以 Vue 初始化的過程中需要遍歷 data 來挾持數據變化,造成速度變慢,內存變大的原因。
而 Vue3 所使用的 Proxy,則是這樣攔截的:
可以看到,proxy 不需要關心具體的 key,它去攔截的是?修改 d ata 上的任意 key ?和?讀取 data 上的任意 key。
所以,不管是已有的 key 還是新增的 key,都會監聽到。但是 Proxy 更加強大的地方還在于 Proxy 除了 get 和 set,還可以攔截更多的操作符,具體可看 MDN。
兼容性
Proxy 對 IE 不友好,vue3 在檢測到使用 IE 的情況下(包括 IE11),會自動降級為 Object.defineProperty 的數據監聽系統。
文/云和數據H5高級工程師,鄭州H5前端開發培訓就來云和數據!