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