vue proxy 的優(yōu)勢與使用場景實現(xiàn)
1.前言
隨著 vue3.x 的消息越來越多, proxy 的討論也。相對于 Object.defineProperty , proxy 有什么區(qū)別,有什么優(yōu)勢,以及可以應(yīng)用在什么地方。該文章就簡單的介紹下
2.Object.defineProperty
講 proxy 之前,先回顧下 Object.defineProperty 。大家都知道, vue2.x 以及之前的版本是使用 Object.defineProperty 實現(xiàn)數(shù)據(jù)的雙向綁定的,至于是怎樣綁定的呢?下面簡單實現(xiàn)一下
function observer(obj) { if (typeof obj ===’object’) { for (let key in obj) { defineReactive(obj, key, obj[key]) } }}function defineReactive(obj, key, value) { //針對value是對象,遞歸檢測 observer(value) //劫持對象的key Object.defineProperty(obj, key, { get() { console.log(’獲取:’+key) return value }, set(val) { //針對所設(shè)置的val是對象 observer(val) console.log(key+'-數(shù)據(jù)改變了') value = val } })}let obj={ name:’守候’, flag:{ book:{ name:’js’, page:325 }, interest:[’火鍋’,’旅游’], }}observer(obj)
在瀏覽器的 console 執(zhí)行一下,似乎能正常運行
但是實際上, Object.defineProperty 問題有以下幾個
問題1.刪除或者增加對象屬性無法監(jiān)聽到
比如增加一個屬性 gender ,由于在執(zhí)行 observer(obj) 的時候,沒有這個屬性,所以這個無法監(jiān)聽到。刪除的屬性也是無法監(jiān)聽到
增加屬性的時候, vue 需要使用 $set 進行操作, $set 的內(nèi)部也是使用 Object.defineProperty 進行操作
問題2.數(shù)組的變化無法監(jiān)聽到
由上圖得知,雖然數(shù)組屬性實際上是修改成功了,但是不能被監(jiān)聽到
問題3. 由于是使用遞歸遍歷對象,使用 Object.defineProperty 劫持對象的屬性,如果遍歷的對象層級比較深,花的時間比較久,甚至有性能的問題
3.proxy
對于 proxy ,在 mdn 上的描述是: 對象用于定義基本操作的自定義行為(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)
簡單來說就是,可以在對目標對象設(shè)置一層攔截。無論對目標對象進行什么操作,都要經(jīng)過這層攔截
聽上去似乎, proxy 比 Object.defineProperty 要好用,并且簡單很多,實際上就是如此。下面用 proxy 對上面的代碼進行改寫試下
function observerProxy(obj){ let handler = { get (target, key, receiver) { console.log(’獲取:’+key) // 如果是對象,就遞歸添加 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 做不到的事情,比如增加一個屬性 gender ,能夠監(jiān)聽到
操作數(shù)組,也能監(jiān)聽到
最后敲一下黑板,簡單總結(jié)一下兩者的區(qū)別
1. Object.defineProperty 攔截的是對象的屬性,會改變原對象。 proxy 是攔截整個對象,通過 new 生成一個新對象,不會改變原對象。
2. proxy 的攔截方式,除了上面的 get 和 set ,還有 11 種。選擇的方式很多 Proxy ,也可以監(jiān)聽一些 Object.defineProperty 監(jiān)聽不到的操作,比如監(jiān)聽數(shù)組,監(jiān)聽對象屬性的新增,刪除等。
4.proxy 使用場景
關(guān)于 proxy 的使用場景,受限于篇幅,這里就簡單列舉幾個,更多的可以移步我的 github 筆記或者 mdn 。
看到這里,兩者的區(qū)別,和 proxy 的優(yōu)勢已經(jīng)知道個大概了。但是在開發(fā)上,有哪些場景可以使用到 proxy 呢,下面列舉個可能會遇上的情況
4-1.負索引數(shù)組
在使用 splice(-1) , slice(-1) 等 API 的時候,當(dāng)輸入負數(shù)的時候,會定位到數(shù)組的最后一項,但是在普通數(shù)組上,并不能使用負數(shù)。 [1,2,3][-1] 這個代碼并不能輸出 3 。要讓上面的代碼輸出 3 , 也可以使用 proxy 實現(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.表單校驗
在對表單的值進行改動的時候,可以在 set 里面進行攔截,判斷值是否合法
let ecValidate = { set (target, key, value, receiver) { if (key === ’age’) { //如果值小于0,或者不是正整數(shù) if (value<0||!Number.isInteger(value)) { throw new TypeError(’請輸入正確的年齡’); } } return Reflect.set(target, key, value, receiver) }}let obj=new Proxy({age:18},ecValidate)obj.age=16obj.age=’少年’
4-3.增加附加屬性
比如有一個需求,保證用戶輸入正確身份證號碼之后,把出生年月,籍貫,性別都添加進用戶信息里面
眾所周知,身份證號碼第一和第二位代表所在省(自治區(qū),直轄市,特別行政區(qū)),第三和第四位代表所在市(地級市、自治州、盟及國家直轄市所屬市轄區(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ù)格式化
比如有一個需求,需要傳時間戳給到后端,但是前端拿到的是一個時間字符串,這個也可以用 proxy 進行攔截,當(dāng)?shù)玫綍r間字符串之后,可以自動加上時間戳。
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)
參考鏈接
Proxy
面試官: 實現(xiàn)雙向綁定Proxy比defineproperty優(yōu)劣如何?
簡單通俗的理解Vue3.0中的Proxy
小結(jié)
proxy 和 Object.defineproperty 的一些區(qū)別,以及 proxy 的優(yōu)勢,使用場景,暫時就介紹到這里了。這篇文章介紹的不算深入,理解圈起來不難。對于 proxy ,筆者也打算繼續(xù)深入學(xué)習(xí),如果往后有收獲,也會第一時間分享。如果文章有什么錯誤,或者有什么建議,歡迎評論區(qū)留言。
到此這篇關(guān)于vue proxy 的優(yōu)勢與使用場景實現(xiàn)的文章就介紹到這了,更多相關(guān)vue proxy 使用場景內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. .Net加密神器Eazfuscator.NET?2023.2?最新版使用教程2. 詳解瀏覽器的緩存機制3. Xml簡介_動力節(jié)點Java學(xué)院整理4. python多線程和多進程關(guān)系詳解5. 一款功能強大的markdown編輯器tui.editor使用示例詳解6. Python xlrd/xlwt 創(chuàng)建excel文件及常用操作7. python 寫函數(shù)在一定條件下需要調(diào)用自身時的寫法說明8. 存儲于xml中需要的HTML轉(zhuǎn)義代碼9. Python 實現(xiàn)勞拉游戲的實例代碼(四連環(huán)、重力四子棋)10. ASP動態(tài)網(wǎng)頁制作技術(shù)經(jīng)驗分享
