前言
前陣子研究了 Vue3 在效能優化的部分,它將原本的 Object.defineProperty 追蹤數值變化的方式汰換成 Proxy 以達到更好的 Reactive 的效果,心想既然 Vue 都做了這層改變,想必 Proxy 一定有它的過人之處吧!
Proxy Description
我們可以為一個 Object 建立 Proxy 物件,並可對其做攔截、重新定義基本的操作 (例如: 尋找屬性、賦值、列舉、函式調用等等)
Proxy 主要由兩個參數組成:
- target: 目標監聽 object
- handler: 當操作代理 object 時,會對該 object 定義哪些操作將會被監聽
沒關係,看到這可能還有些模糊,下面舉一個簡單例子。該例子會針對以上兩個參數做簡單的呈現。
1 ~ 3 行:建立目標代理 object
5 行:建立 hadler 物件
7 行:建立 Proxy 服務,把目標要代理的 object 放在第一個參數並把 handler 放在第二個參數
可以看到最後 console 出來的 age 依然是 15,因為我們的 handler 為空物件,裡面沒有指定要針對什麼樣的操作進行額外的處理,所以返回的依然是原始資料。
我們接著在 handler 裡面加些操作,這裡只會展示比較基本的 set, get handler,但代理操作總共有 13 種方式,其餘可參考 Proxy() Constructor。
- handler.get()
主要用於取得目標屬性的值。
當console.log(p.name)
可以看到 get()
有個判斷式, property === 'name'
幫我把 target 原本的 name 改為 Tom 並作回傳。
2. handler.set()
主要用於設定目標屬性的值。
可能有人認為 30 行設定 p.age = 25
為什麼最終返回 35 呢?
原因是 proxy_handler 知道我要對目標 Object 做 set 的動作,因此當我設定完 age
之後程式接著進入 14 行的 set()
並對傳入的值 +5 再存入,這時 age = 30
。
最後當我要取出 age
時,程式會進入 8 行的 get()
並對要取出的值 +5 後再回傳出去,因此最後得出 age = 35
。
最後來延伸閱讀 Reflect 到底何方神聖!
Reflect Description
這邊依舊只會提到 Reflect 的功能介紹,至於為什麼 Proxy 會與 Reflect 做搭配以及 Proxy 如何應用在更多地方,我會再另外開個主題做解說~
Reflect 是一個 JS 內建的物件,專門提供攔截 JS 操作的方法。且不同於多數的全域物件,Reflect 不是建構子,我們無法使用 new
或是用調用 (invoke) 函式的方式來呼叫它。
Reflect 全部的屬性及方法都是靜態的 (類似 Math),且它也提供了跟 Proxy handler 一樣的 13 種靜態方法供我們使用,可參考 Static methods。
以下一樣通過 Reflect 提供的 get, set 做基本的功能展示。
結論
其實 Proxy, Reflect 還有很多好玩好用的方法 (不只做攔截監聽使用),我會盡快理解再繼續附上我吸收轉化後的觀念持續幫助自己進步也讓有需要的人可以藉由我的文章有更多的認識。