Proxy的用法:
用于修改某個(gè)變量的默認(rèn)數(shù)據(jù)操作簇秒,代理新的寫(xiě)法偎行。
語(yǔ)法如下:
const person = {name: 'xiaolu',age: 'secret'}
const handle = {
get: function(target,key,property) {},
set: function(target,key,property) {}
}
let proxyPerson = new Proxy(person,handler); // person是要代理的對(duì)象,handler是代理的對(duì)象的操作方法
熱門(mén)應(yīng)用:
優(yōu)化Vue3的響應(yīng)式
如我們所知,Vue2的響應(yīng)式其實(shí)存在一些缺點(diǎn),比如需要深度監(jiān)聽(tīng)藏姐,一次性遞歸到底,計(jì)算量大该贾,無(wú)法監(jiān)聽(tīng)新增和刪除的屬性羔杨,無(wú)法監(jiān)聽(tīng)數(shù)組的新增和刪除方法,Proxy可以?xún)?yōu)化這些缺點(diǎn)杨蛋,但Proxy也有不足问畅,它的兼容性并不是特別好,需要針對(duì)某些瀏覽器寫(xiě)補(bǔ)丁六荒。目前先學(xué)習(xí)它是如何優(yōu)化Vue2.x的缺點(diǎn)护姆。在學(xué)習(xí)之前需要先引入Reflect這個(gè)概念。
Reflect
Reflect是為操作對(duì)象而設(shè)計(jì)的API掏击,它是為了優(yōu)化Object上面的一些工具函數(shù)卵皂,舉個(gè)例子:
Object.defineProperty(target,key,{
get: {} // 當(dāng)觸發(fā)讀取操作時(shí)回調(diào)
set: {} // 當(dāng)觸發(fā)寫(xiě)的操作時(shí)回調(diào)
})
這個(gè)工具方法給get和set方法賦回調(diào)函數(shù),Reflect方法對(duì)應(yīng)的寫(xiě)法是
Reflect.get(target,key,property)
Reflect.set(target,key,property)
總結(jié)一下砚亭,Reflect就是為了凈化Object,因?yàn)镺bject越來(lái)越笨重灯变。
Vue3實(shí)現(xiàn)響應(yīng)式
1.簡(jiǎn)單的代理,不加任何操作
打印可以看到捅膘,修改set沒(méi)有成功添祸,因?yàn)閟et方法已經(jīng)被代理覆蓋了,且并沒(méi)有寫(xiě)賦值操作寻仗,之前的不起作用了刃泌,那么如果想要set生效,需要用Reflect加上如下的代碼:
let result = Reflect.set(target,name,property) ,即調(diào)用底層的set方法耙替。
為什么要用Reflect呢亚侠?我也不知道,官方就是這么推薦的俗扇,Proxy和Reflect算是一對(duì)好兄弟吧硝烂,Proxy能代理的方法,Reflect也都有對(duì)應(yīng)的操作方法铜幽,下面開(kāi)始進(jìn)入正題滞谢。
2.響應(yīng)式寫(xiě)法
Object.defineProperty()這個(gè)方法添加的set屬性有先后順序,就是必須先給屬性加了這個(gè)方法除抛,后續(xù)修改賦值的時(shí)候狮杨,才會(huì)觸發(fā)set方法,所以就會(huì)有新增和刪除無(wú)法響應(yīng)的缺點(diǎn)镶殷。
Proxy優(yōu)化這個(gè)缺點(diǎn)的思路就是禾酱,直接代理了讀和取微酬,我詳細(xì)描述一下:
1.通過(guò)Object.defineProperty(person,name,{
get: {}
set: {}
}) 監(jiān)聽(tīng)name屬性的set
person.name = 'hahaha' 執(zhí)行這段代碼绘趋,person會(huì)先調(diào)用person內(nèi)置的set方法,然后再執(zhí)行上面的set方法颗管,那么新增一個(gè)city屬性呢陷遮,
person.city = '深圳'
很顯然無(wú)法監(jiān)聽(tīng)到,因?yàn)樯厦娌](méi)有針對(duì)city綁定set和get方法
2.通過(guò)Proxy監(jiān)聽(tīng)
proxyPerson.name = 'hahaha' 執(zhí)行這段代碼垦江,person會(huì)試圖調(diào)用person內(nèi)置的set方法帽馋,然而因?yàn)閜roxyPerson這個(gè)實(shí)例已經(jīng)全權(quán)代理了person的get和set,所以?xún)?nèi)置的原始的get和set方法不生效了比吭,反而是直接執(zhí)行proxyPerson代理的set方法绽族,所以必須要調(diào)用Reflect.set去修改屬性,很搞笑吧衩藤,因?yàn)榈讓痈傻幕頿roxyPerson全部接過(guò)來(lái)了吧慢,這樣實(shí)現(xiàn)響應(yīng)式是不是就解決了無(wú)法監(jiān)聽(tīng)新增和刪除屬性了呢?實(shí)現(xiàn)監(jiān)聽(tīng)對(duì)象新增刪除的代碼:
3.深度監(jiān)聽(tīng)
還需要加入深度監(jiān)聽(tīng)的邏輯赏表,等等检诗,不是直接代理對(duì)象就完了嗎?然而并不是瓢剿,proxy代理的只是對(duì)象的第一層屬性逢慌,深度層級(jí)的屬性需要另外代理,代碼如下:
添加紅色框內(nèi)的代碼
控制臺(tái)查看發(fā)現(xiàn)city屬性也變成了proxy實(shí)例