前幾天,我一個做前端的朋友阿強(qiáng),凌晨一點(diǎn)給我發(fā)消息: “兄弟,我代碼沒報(bào)錯,但數(shù)據(jù)就是不對勁。”
我一看,好家伙,他在調(diào)一個后臺管理系統(tǒng)。頁面里明明已經(jīng)修改了對象數(shù)據(jù),但有些地方完全感知不到變化, 他說:“JavaScript 對象就像個沒人管的倉庫,誰都能進(jìn)去改,改完還沒人通知我。”
我當(dāng)時就笑了: “你這不是缺個保安嗎?”, 他說:“啥保安?”
我回了兩個字: “Proxy。”, 很多人第一次學(xué) JavaScript Proxy(代理)的時候,上來就是各種 get、set、攔截器、Reflect,一頓猛學(xué),結(jié)果越學(xué)越懵, 其實(shí) Proxy 最核心的概念特別簡單, 你可以把它理解成: “給對象門口安排了一個門衛(wèi)。”, 以后別人想訪問對象,不再直接進(jìn)去,而是先經(jīng)過門衛(wèi), 這個門衛(wèi)可以:
放行
攔截
記錄
修改
甚至騙人
今天咱們就從最基礎(chǔ)的開始, 先聊聊 “創(chuàng)建空代理。”, 別小看這個知識點(diǎn), 很多高級玩法,全是從這里長出來的。
什么是代理?
先看一個普通對象。
![]()
這段代碼沒什么特別的, 訪問 user.name 時,程序直接去對象里拿值, 流程是程序 -> 對象。
但是 Proxy 出現(xiàn)后,流程變成了程序 -> 代理 -> 對象, 中間多了一個“中間商”, 這就是代理。
創(chuàng)建一個空代理
最基礎(chǔ)的 Proxy 寫法長這樣:
![]()
這里有兩個參數(shù): newProxy(target, handler)
target: 被代理的對象
handler: 代理配置對象
而所謂“空代理”,就是: {}, handler 里面什么都不寫, 很多人看到這里會問 “啥都不寫,那代理有啥意義?”
別急, 這里其實(shí)特別像 你新開了一家商場, 保安已經(jīng)站門口了, 但老板還沒給他任何規(guī)則, 所以現(xiàn)在:
誰來都放行
誰走都不管
不記錄
不檢查
也就是說 “代理已經(jīng)存在,但不干涉任何行為。”
空代理到底有什么效果?
咱們直接測試。
![]()
輸出 小米, 看起來跟普通對象一模一樣, 再試試修改。
![]()
輸出 老王, 你會發(fā)現(xiàn) 修改代理對象, 原對象也變了, 因?yàn)榇肀举|(zhì)上并不是“復(fù)制對象”, 它只是 “站在對象前面。”, 真正的數(shù)據(jù) 還是原對象那份, 這個特別重要。
很多人誤以為 constproxy=newProxy(user, {});, 等于克隆了一份對象, 其實(shí)完全不是, 它們共享同一份數(shù)據(jù), 就像 你找了個房產(chǎn)中介, 房子還是那套房子, 中介不是重新蓋了一套。
代理和目標(biāo)對象的關(guān)系
咱們再做個實(shí)驗(yàn)。
![]()
輸出 31, 再反過來。
![]()
輸出 上海, 說明什么?
說明 代理和目標(biāo)對象的數(shù)據(jù)是聯(lián)動的。 本質(zhì)上:
proxy -> target
proxy 并沒有自己的數(shù)據(jù)存儲。
它只是訪問 target。
空代理最大的價值是什么?
很多人學(xué)到這里會覺得 “這不啥也沒干嗎?”, 其實(shí)恰恰相反, 空代理最大的價值是 “先建立代理通道。”, 什么意思?
你先把所有訪問路徑都改成程序 -> Proxy -> 對象,以后想加任何規(guī)則 都能直接往 handler 里塞, 比如:
日志記錄
數(shù)據(jù)校驗(yàn)
權(quán)限控制
響應(yīng)式更新
數(shù)據(jù)監(jiān)聽
緩存處理
全都可以后期擴(kuò)展, 這特別像什么? 特別像小區(qū)門禁系統(tǒng), 剛開始可能只是個擺設(shè), 但以后:
刷臉
指紋
訪客登記
黑名單
自動報(bào)警
都能往上加。 Vue3 為什么使用 Proxy 實(shí)現(xiàn)響應(yīng)式?
核心原因就是 它能攔截對象操作。
空代理和原對象不相等
注意一個非常容易踩坑的點(diǎn)。
![]()
輸出 false, 雖然它們操作的是同一份數(shù)據(jù), 但 它們不是同一個對象, 這一點(diǎn)特別像 老板和老板秘書。
秘書能代表老板做很多事。
但秘書不是老板。
一個非常經(jīng)典的面試題
面試官特別喜歡問:
![]()
輸出什么?
很多新人會猶豫, 其實(shí)答案就是老王, 因?yàn)榇聿僮鞯模?本質(zhì)還是目標(biāo)對象。
為什么Vue3放棄Object.defineProperty?
以前 Vue2 用的是 Object.defineProperty, 它的問題特別多, 比如:
無法監(jiān)聽新增屬性
無法監(jiān)聽刪除屬性
數(shù)組監(jiān)聽麻煩
深層對象遞歸性能差
Proxy 就不一樣了, 它像一個真正的“門衛(wèi)”, 無論:
讀取
修改
刪除
判斷屬性
遍歷對象
它都能知道, 這也是為什么 Vue3 的響應(yīng)式系統(tǒng)比 Vue2 更強(qiáng), 而這一切, 都從 newProxy(target, handler) 開始。
真正厲害的不是代理,而是“攔截”
空代理只是第一步, 真正牛的是 handler 里面那些攔截器, 比如:
get
set
deleteProperty
has
ownKeys
這些能力意味著 JavaScript 終于能對對象行為進(jìn)行“編程”了。
以前對象像一個裸奔倉庫。
現(xiàn)在對象像一個帶安檢系統(tǒng)的大樓。
所有人進(jìn)出, 全都能控制。
總結(jié)
今天咱們聊的其實(shí)只是 Proxy 最基礎(chǔ)的知識 “創(chuàng)建空代理。”, 代碼也很簡單 constproxy=newProxy(target, {});, 但這個東西特別像武俠小說里的 “打通任督二脈。”, 剛開始看著平平無奇, 但后面:
Vue3 響應(yīng)式
數(shù)據(jù)劫持
權(quán)限控制
API校驗(yàn)
自動日志
狀態(tài)管理
很多高級玩法 全都建立在它上面, 所以別小看這個“空代理”, 它雖然現(xiàn)在什么都沒干, 但它最大的意義是 “從今天開始,所有訪問對象的人,都得先經(jīng)過我。”
好朋友們,我們下篇見~
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.