Vue3.0 開始用 Proxy 代替 Object.defineProperty了,這篇文章結合實體教你如何使用Proxy
本篇文章同時收錄【前端知識點】中,鏈接直達
閱讀本文您將識訓
JavaScript中的Proxy是什么?能干什么?Vue3.0開始為什么用Proxy代替Object.defineProperty
Proxy 是什么
解釋參考MDN,鏈接直達
名詞解釋
- Proxy 物件用于定義基本操作的自定義行為(如屬性查找、賦值、列舉、函式呼叫等)
- Proxy 用于修改某些操作的默認行為,也可以理解為在目標物件之前架設一層攔截,外部所有的訪問都必須先通過這層攔截,因此提供了一種機制,可以對外部的訪問進行過濾和修改
語法
const p = new Proxy(target, handler)target: 要使用 Proxy 包裝的目標物件(可以是任何型別的物件,包括原生陣列,函式,甚至另一個代理)handler: 對該代理物件的各種操作行為處理(為空物件的情況下,基本可以理解為是對第一個引數做的一次淺拷貝)
- 簡而言之:
target就是你想要代理的物件;而handler是一個函式物件,其中定義了所有你想替target代為管理的操作物件,包含了:- *
handler.has(target, prop):in運算子的捕捉器,攔截HasProperty操作 - *
handler.get(target, prop): 屬性讀取操作的捕捉器 - *
handler.set(target, prop, value): 屬性設定操作的捕捉器 - *
handler.apply(target, object, args): 函式呼叫操作的捕捉器,攔截函式的呼叫、call和apply操作 handler.getPrototypeOf():Object.getPrototypeOf方法的捕捉器handler.setPrototypeOf():Object.setPrototypeOf方法的捕捉器handler.isExtensible():Object.isExtensible方法的捕捉器handler.preventExtensions():Object.preventExtensions方法的捕捉器handler.getOwnPropertyDescriptor():Object.getOwnPropertyDescriptor方法的捕捉器handler.defineProperty():Object.defineProperty方法的捕捉器handler.deleteProperty():delete運算子的捕捉器handler.ownKeys():Object.getOwnPropertyNames方法和Object.getOwnPropertySymbols方法的捕捉器handler.construct(): new 運算子的捕捉器
- *
- 注意:如果一個屬性
不可配置||不可寫,則該屬性不可被代理,通過Proxy訪問該屬性會報錯, *標記的trap為本文都要涉及到的
Proxy 能干什么?
當你想進行以下操作時proxy模式通常會很有用:
- 攔截或控制對某個物件的訪問
- 通過隱藏事務或輔助邏輯來減小方法/類的復雜性
- 防止在未經驗證/準備的情況下執行重度依萊澩的操作
一:javascript中真正的私有變數/攔截has...in...操作/給出提示資訊或是阻止特定操作
傳統方法私有變數可獲取可修改
Proxy 設定私有變數
- 針對私有變數,可以使用一個proxy來截獲針對某個屬性的請求并作出限制或是直接回傳
undefined - 還可以使用
hastrap 來掩蓋這個屬性的存在
-
has方法攔截的是hasProperty操作,不是hasOwnProperty,所以has...in方法不判斷一個屬性是自身屬性還是繼承的屬性 -
注意:
has...in可以攔截到,for...in攔截不到 -
阻止其他人洗掉屬性,想讓呼叫方法的人知道該方法已經被廢棄,或是想阻止其他人修改屬性
- 注意: 要是
Proxy代理起作用,必須針對Proxy的實體進行操作,而不是針對目標物件進行操作
二:資料校驗(看代碼)
- 利用 Proxy 代理進行簡單資料校驗
- 校驗邏輯直接加在代理處理函式中過于繁重,我們可以把校驗模塊直接抽離出來,只需要去處理校驗的邏輯,代理層面后續不需要改動

三:利用proxy進行記錄物件訪問
-
針對那些重度依萊澩,執行緩慢或是頻繁使用的方法或介面,統計它們的使用或是性能
-
可以記錄各種各樣的資訊而不用修改應用程式的代碼或是阻塞代碼執行,并且只需要在這些代碼的基礎上稍事修改就可以記錄特性函式的執行性能

-
以上例子就是一個監聽函式執行的代理,可以將其進行擴展為打點函式
-
這里面
Proxy的trap為什么使用get而不是apply? 答案
四:普通函式與建構式的兼容
- 建構式呼叫沒有使用new關鍵字來呼叫的話,Class物件會直接拋出例外
- 使用
Proxy進行封裝讓建構式也能夠直接進行函式呼叫

五:深層取值判斷(看代碼)
-
需要解決的幾個問題
- 獲取資料進行攔截
xxx.xxx.xxx...無論undefined出現在哪里都不能報錯Proxy的get()傳入的引數必須是物件
-
傳統方式深層取值繁瑣,利用Proxy可以簡化不必要代碼

-
但是當
target[prop]是undefined的時候,Proxy get()的入參變成了undefined,但Proxy第一個入參必須為物件 -
需要對 obj 為
undefined的時候進行特殊處理,為了能夠深層取值,所以使用一個空函式進行設定攔截,利用applytrap 進行處理

-
我們理想中的應該是,如果屬性為
undefined就回傳undefined,但仍要支持訪問下級屬性,而不是拋出錯誤 -
順著這個思路來的話,很明顯當屬性為
undefined的時候也需要用Proxy進行特殊處理
所以我們需要一個具有下面特性的get()方法
getData(undefined)() === undefined; // true
getData(undefined).xxx.yyy.zzz(); // undefined
- 這里完全不需要注意
get(undefined).xxx是否為正確的值,因為想獲取值必須要執行才能拿到 - 那么只需要對所有
undefined后面訪問的屬性都默認為undefined就好了,所以我們需要一個代理了undefined后的回傳物件 - 同時為了解決無限回圈執行的問題,當第一次檢測到出現
undefined的時候,停止執行

六:日志上報
- 騰訊利用Proxy進行日志上報功能
Vue 3.0 的 Proxy & Object.defineProperty
Proxy
- 劫持方式:代理整個物件,只需做一層代理就可以監聽同級結構下的所有屬性變化,包括新增屬性和洗掉屬性
- 本質:
Proxy本質上屬于元編程非破壞性資料劫持,在原物件的基礎上進行了功能的衍生而又不影響原物件,符合松耦合高內聚的設計理念
Object.defineProperty
- 劫持方式:只能劫持物件的屬性,不能直接代理物件
- 流程:get中進行依賴收集,set資料時通知訂閱者更新
- 存在的問題:雖然
Object.defineProperty通過為屬性設定getter/setter能夠完成資料的回應式,但是它并不算是實作資料的回應式的完美方案,某些情況下需要對其進行修補或者hack,這也是它的缺陷,主要表現在兩個方面:- 無法檢測到物件屬性的新增或洗掉
- 不能監聽陣列的變化

1. Object.defineProperty 無法監聽新增加的屬性
- 解決方式:提供方法重新手動Observe,需要監聽的話使用
Vue.set()重新設定添加屬性的回應式

2. Object.defineProperty 無法一次性監聽物件所有屬性,如物件屬性的子屬性
- 解決方式: 通過遞回呼叫來實作子屬性回應式

3. Object.defineProperty 無法回應陣列操作
- 解決方式:通過遍歷和重寫Array陣列原型方法操作方法實作,但是也只限制在
push/pop/shift/unshift/splice/sort/reverse這七個方法,其他陣列方法及陣列的使用則無法檢測到,也無法監聽陣列索引的變化和長度的變更
4. Proxy 攔截方式更多, Object.defineProperty 只有 get 和 set
5. Proxy 性能問題
Proxy的性能比Promise還差Proxy作為新標準,從長遠來看,JS 引擎會繼續優化Proxy- Thoughts on ES6 Proxies Performance
- ES6 Proxy 性能之我見
6. Proxy 兼容性差
Vue 3.0中放棄了對于IE的支持(以為Vue 3.0中會對不兼容的瀏覽器進行向下兼容,但是經過查看資料和原始碼發現尤大壓根沒做兼容)- 目前并沒有一個完整支持
Proxy所有攔截方法的Polyfill方案,有一個google撰寫的proxy-polyfill也只支持了get/set/apply/construct四種攔截
多說一嘴 Decorator
- ES7 中實作的
Decorator,相當于設計模式中的裝飾器模式, - 如果簡單地區分
Proxy和Decorator的使用場景,可以概括為:Proxy的核心作用是控制外界對被代理者內部的訪問,Decorator的核心作用是增強被裝飾者的功能,
寫在最后
- 如果你覺得這篇文章對你有益,煩請點贊以及分享給更多需要的人!
快到碗里來!百度校招還有HC!甩簡歷來!
極速直接內推【位元組跳動】&【百度】&【猿輔導】&【京東】
歡迎關注微信公眾號【全堆疊道路】,獲取更多科技相關知識及免費書籍,
更多好文
幾行代碼教你解決微信生成海報及二維碼
冷門的HTML - tabindex 的作用
[萬字長文]百度和好未來面試經含答案
[前端面試]前端快取問題看這篇,讓面試官愛上你
記一次慘痛的Vue-cli + VueX + SSR經歷
[三分鐘小文]前端性能優化-HTML、CSS、JS部分
[三分鐘小文]前端性能優化-頁面加載速度優化
[三分鐘小文]前端性能優化-網路傳輸層優化
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/227127.html
標籤:其他
下一篇:仿美團外賣的店鋪串列獲取思路
