vue proxy 的優(yōu)勢(shì)與使用場(chǎng)景實(shí)現(xiàn)
1.前言
隨著 vue3.x 的消息越來(lái)越多, proxy 的討論也。相對(duì)于 Object.defineProperty , proxy 有什么區(qū)別,有什么優(yōu)勢(shì),以及可以應(yīng)用在什么地方。該文章就簡(jiǎn)單的介紹下
2.Object.defineProperty
講 proxy 之前,先回顧下 Object.defineProperty 。大家都知道, vue2.x 以及之前的版本是使用 Object.defineProperty 實(shí)現(xiàn)數(shù)據(jù)的雙向綁定的,至于是怎樣綁定的呢?下面簡(jiǎn)單實(shí)現(xiàn)一下
function observer(obj) {
if (typeof obj ==='object') {
for (let key in obj) {
defineReactive(obj, key, obj[key])
}
}
}
function defineReactive(obj, key, value) {
//針對(duì)value是對(duì)象,遞歸檢測(cè)
observer(value)
//劫持對(duì)象的key
Object.defineProperty(obj, key, {
get() {
console.log('獲?。?+key)
return value
},
set(val) {
//針對(duì)所設(shè)置的val是對(duì)象
observer(val)
console.log(key+"-數(shù)據(jù)改變了")
value = val
}
})
}
let obj={
name:'守候',
flag:{
book:{
name:'js',
page:325
},
interest:['火鍋','旅游'],
}
}
observer(obj)
在瀏覽器的 console 執(zhí)行一下,似乎能正常運(yùn)行

但是實(shí)際上, Object.defineProperty 問(wèn)題有以下幾個(gè)
問(wèn)題1.刪除或者增加對(duì)象屬性無(wú)法監(jiān)聽(tīng)到
比如增加一個(gè)屬性 gender ,由于在執(zhí)行 observer(obj) 的時(shí)候,沒(méi)有這個(gè)屬性,所以這個(gè)無(wú)法監(jiān)聽(tīng)到。刪除的屬性也是無(wú)法監(jiān)聽(tīng)到
增加屬性的時(shí)候, vue 需要使用 $set 進(jìn)行操作, $set 的內(nèi)部也是使用 Object.defineProperty 進(jìn)行操作

問(wèn)題2.數(shù)組的變化無(wú)法監(jiān)聽(tīng)到

由上圖得知,雖然數(shù)組屬性實(shí)際上是修改成功了,但是不能被監(jiān)聽(tīng)到
問(wèn)題3. 由于是使用遞歸遍歷對(duì)象,使用 Object.defineProperty 劫持對(duì)象的屬性,如果遍歷的對(duì)象層級(jí)比較深,花的時(shí)間比較久,甚至有性能的問(wèn)題
3.proxy
對(duì)于 proxy ,在 mdn 上的描述是: 對(duì)象用于定義基本操作的自定義行為(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)
簡(jiǎn)單來(lái)說(shuō)就是,可以在對(duì)目標(biāo)對(duì)象設(shè)置一層攔截。無(wú)論對(duì)目標(biāo)對(duì)象進(jìn)行什么操作,都要經(jīng)過(guò)這層攔截
聽(tīng)上去似乎, proxy 比 Object.defineProperty 要好用,并且簡(jiǎn)單很多,實(shí)際上就是如此。下面用 proxy 對(duì)上面的代碼進(jìn)行改寫(xiě)試下
function observerProxy(obj){
let handler = {
get (target, key, receiver) {
console.log('獲?。?+key)
// 如果是對(duì)象,就遞歸添加 proxy 攔截
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], handler)
}
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log(key+"-數(shù)據(jù)改變了")
return Reflect.set(target, key, value, receiver)
}
}
return new Proxy(obj, handler)
}
let obj={
name:'守候',
flag:{
book:{
name:'js',
page:325
},
interest:['火鍋','旅游'],
}
}
let objTest=observerProxy(obj)
也是一樣的效果

而且,能做到 Object.defineProperty 做不到的事情,比如增加一個(gè)屬性 gender ,能夠監(jiān)聽(tīng)到

操作數(shù)組,也能監(jiān)聽(tīng)到

最后敲一下黑板,簡(jiǎn)單總結(jié)一下兩者的區(qū)別
1. Object.defineProperty 攔截的是對(duì)象的屬性,會(huì)改變?cè)瓕?duì)象。 proxy 是攔截整個(gè)對(duì)象,通過(guò) new 生成一個(gè)新對(duì)象,不會(huì)改變?cè)瓕?duì)象。
2. proxy 的攔截方式,除了上面的 get 和 set ,還有 11 種。選擇的方式很多 Proxy ,也可以監(jiān)聽(tīng)一些 Object.defineProperty 監(jiān)聽(tīng)不到的操作,比如監(jiān)聽(tīng)數(shù)組,監(jiān)聽(tīng)對(duì)象屬性的新增,刪除等。
4.proxy 使用場(chǎng)景
關(guān)于 proxy 的使用場(chǎng)景,受限于篇幅,這里就簡(jiǎn)單列舉幾個(gè),更多的可以移步我的 github 筆記或者 mdn 。
看到這里,兩者的區(qū)別,和 proxy 的優(yōu)勢(shì)已經(jīng)知道個(gè)大概了。但是在開(kāi)發(fā)上,有哪些場(chǎng)景可以使用到 proxy 呢,下面列舉個(gè)可能會(huì)遇上的情況
4-1.負(fù)索引數(shù)組
在使用 splice(-1) , slice(-1) 等 API 的時(shí)候,當(dāng)輸入負(fù)數(shù)的時(shí)候,會(huì)定位到數(shù)組的最后一項(xiàng),但是在普通數(shù)組上,并不能使用負(fù)數(shù)。 [1,2,3][-1] 這個(gè)代碼并不能輸出 3 。要讓上面的代碼輸出 3 , 也可以使用 proxy 實(shí)現(xiàn)。
let ecArrayProxy = {
get (target, key, receiver) {
let _index=key<0?target.length+Number(key):key
return Reflect.get(target, _index, receiver)
}
}
let arr=new Proxy([1,2,3],ecArrayProxy)
4-2.表單校驗(yàn)
在對(duì)表單的值進(jìn)行改動(dòng)的時(shí)候,可以在 set 里面進(jìn)行攔截,判斷值是否合法
let ecValidate = {
set (target, key, value, receiver) {
if (key === 'age') {
//如果值小于0,或者不是正整數(shù)
if (value<0||!Number.isInteger(value)) {
throw new TypeError('請(qǐng)輸入正確的年齡');
}
}
return Reflect.set(target, key, value, receiver)
}
}
let obj=new Proxy({age:18},ecValidate)
obj.age=16
obj.age='少年'
4-3.增加附加屬性
比如有一個(gè)需求,保證用戶輸入正確身份證號(hào)碼之后,把出生年月,籍貫,性別都添加進(jìn)用戶信息里面
眾所周知,身份證號(hào)碼第一和第二位代表所在?。ㄗ灾螀^(qū),直轄市,特別行政區(qū)),第三和第四位代表所在市(地級(jí)市、自治州、盟及國(guó)家直轄市所屬市轄區(qū)和縣的匯總碼)。第七至第十四位是出生年月日。低17位代表性別,男單女雙。
const PROVINCE_NUMBER={
44:'廣東省',
46:'海南省'
}
const CITY_NUMBER={
4401:'廣州市',
4601:'??谑?
}
let ecCardNumber = {
set (target, key, value, receiver) {
if(key === 'cardNumber'){
Reflect.set(target, 'hometown', PROVINCE_NUMBER[value.substr(0,2)]+CITY_NUMBER[value.substr(0,4)], receiver)
Reflect.set(target, 'date', value.substr(6,8), receiver)
Reflect.set(target, 'gender', value.substr(-2,1)%2===1?'男':'女', receiver)
}
return Reflect.set(target, key, value, receiver)
}
}
let obj=new Proxy({cardNumber:''},ecCardNumber)
4-4.數(shù)據(jù)格式化
比如有一個(gè)需求,需要傳時(shí)間戳給到后端,但是前端拿到的是一個(gè)時(shí)間字符串,這個(gè)也可以用 proxy 進(jìn)行攔截,當(dāng)?shù)玫綍r(shí)間字符串之后,可以自動(dòng)加上時(shí)間戳。
let ecDate = {
set (target, key, value, receiver) {
if(key === 'date'){
Reflect.set(target, 'timeStamp', +new Date(value), receiver)
}
return Reflect.set(target, key, value, receiver)
}
}
let obj=new Proxy({date:''},ecDate)
參考鏈接
面試官: 實(shí)現(xiàn)雙向綁定Proxy比defineproperty優(yōu)劣如何?
小結(jié)
proxy 和 Object.defineproperty 的一些區(qū)別,以及 proxy 的優(yōu)勢(shì),使用場(chǎng)景,暫時(shí)就介紹到這里了。這篇文章介紹的不算深入,理解圈起來(lái)不難。對(duì)于 proxy ,筆者也打算繼續(xù)深入學(xué)習(xí),如果往后有收獲,也會(huì)第一時(shí)間分享。如果文章有什么錯(cuò)誤,或者有什么建議,歡迎評(píng)論區(qū)留言。
到此這篇關(guān)于vue proxy 的優(yōu)勢(shì)與使用場(chǎng)景實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue proxy 使用場(chǎng)景內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue中如何實(shí)現(xiàn)proxy代理
- 詳解Vuejs2.0 如何利用proxyTable實(shí)現(xiàn)跨域請(qǐng)求
- vue cli3 配置proxy代理無(wú)效的解決
- 詳解vue-cli項(xiàng)目中的proxyTable跨域問(wèn)題小結(jié)
- 解決vue中使用proxy配置不同端口和ip接口問(wèn)題
- vue2.0設(shè)置proxyTable使用axios進(jìn)行跨域請(qǐng)求的方法
- vue proxyTable 接口跨域請(qǐng)求調(diào)試的示例
- 使用proxy實(shí)現(xiàn)一個(gè)更優(yōu)雅的vue【推薦】
- Vue使用Proxy監(jiān)聽(tīng)所有接口狀態(tài)的方法實(shí)現(xiàn)
- 初探Vue3.0 中的一大亮點(diǎn)Proxy的使用
- vue 實(shí)現(xiàn)cli3.0中使用proxy進(jìn)行代理轉(zhuǎn)發(fā)
相關(guān)文章
vue 使用class創(chuàng)建和清除水印的示例代碼
這篇文章主要介紹了vue 使用class創(chuàng)建和清除水印的示例代碼,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下2020-12-12
vue2.0開(kāi)發(fā)實(shí)踐總結(jié)之入門(mén)篇
這篇文章主要為大家總結(jié)了vue2.0開(kāi)發(fā)實(shí)踐之入門(mén),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
詳解VUE 定義全局變量的幾種實(shí)現(xiàn)方式
本篇文章主要介紹了VUE 全局變量的幾種實(shí)現(xiàn)方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
vue+webrtc(騰訊云) 實(shí)現(xiàn)直播功能的實(shí)踐
本文主要介紹了vue+webrtc(騰訊云) 實(shí)現(xiàn)直播功能的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
Vue自定義指令上報(bào)Google Analytics事件統(tǒng)計(jì)的方法
我們經(jīng)常需要接入統(tǒng)計(jì)服務(wù)以方便運(yùn)營(yíng),這篇文章主要介紹了Vue自定義指令上報(bào)Google Analytics事件統(tǒng)計(jì)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
vue中使用iconfont圖標(biāo)的過(guò)程
這篇文章主要介紹了vue中使用iconfont圖標(biāo)的過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
前端實(shí)現(xiàn)簡(jiǎn)單的sse封裝方式(React hook Vue3)
這篇文章主要介紹了前端實(shí)現(xiàn)簡(jiǎn)單的sse封裝方式(React hook Vue3),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08

