Vue3.0 開始用 Proxy 代替 Object.defineProperty了,這篇文章結合實例教你如何使用Proxyjavascript
本篇文章同時收錄【前端知識點】中,連接直達html
JavaScript
中的 Proxy
是什麼?能幹什麼?Vue3.0
開始爲何用 Proxy
代替 Object.defineProperty
Proxy
是什麼解釋參考MDN,連接直達前端
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
能幹什麼?undefined
has
trap 來掩蓋這個屬性的存在has
方法攔截的是 hasProperty
操做,不是 hasOwnProperty
,因此 has...in
方法不判斷一個屬性是自身屬性仍是繼承的屬性vue
注意: has...in
能夠攔截到,for...in
攔截不到java
阻止其餘人刪除屬性,想讓調用方法的人知道該方法已經被廢棄,或是想阻止其餘人修改屬性git
Proxy
代理起做用,必須針對 Proxy
的實例進行操做,而不是針對目標對象進行操做針對那些重度依賴資源,執行緩慢或是頻繁使用的方法或接口,統計它們的使用或是性能es6
能夠記錄各類各樣的信息而不用修改應用程序的代碼或是阻塞代碼執行。而且只須要在這些代碼的基礎上稍事修改就能夠記錄特性函數的執行性能
github
以上例子就是一個監聽函數執行的代理,能夠將其進行擴展爲打點函數面試
這裏面 Proxy
的 trap
爲何使用 get
而不是 apply
? 答案編程
Proxy
進行封裝讓構造函數也可以直接進行函數調用須要解決的幾個問題
xxx.xxx.xxx...
不管 undefined
出如今哪裏都不能報錯Proxy
的 get()
傳入的參數必須是對象傳統方式深層取值繁瑣,利用Proxy能夠簡化沒必要要代碼
可是當 target[prop]
是 undefined
的時候,Proxy get()
的入參變成了 undefined
,但 Proxy
第一個入參必須爲對象
須要對 obj 爲 undefined
的時候進行特殊處理,爲了可以深層取值,因此使用一個空函數進行設置攔截,利用 apply
trap 進行處理
咱們理想中的應該是,若是屬性爲 undefined
就返回 undefined
,但仍要支持訪問下級屬性,而不是拋出錯誤
順着這個思路來的話,很明顯當屬性爲 undefined
的時候也須要用 Proxy
進行特殊處理
因此咱們須要一個具備下面特性的 get()
方法
getData(undefined)() === undefined; // true getData(undefined).xxx.yyy.zzz(); // undefined
get(undefined).xxx
是否爲正確的值,由於想獲取值必需要執行才能拿到undefined
後面訪問的屬性都默認爲 undefined
就行了,因此咱們須要一個代理了 undefined
後的返回對象undefined
的時候,中止執行Proxy
本質上屬於元編程非破壞性數據劫持,在原對象的基礎上進行了功能的衍生而又不影響原對象,符合鬆耦合高內聚的設計理念Object.defineProperty
經過爲屬性設置 getter/setter
可以完成數據的響應式,可是它並不算是實現數據的響應式的完美方案,某些狀況下須要對其進行修補或者hack,這也是它的缺陷,主要表如今兩個方面:
Vue.set()
從新設置添加屬性的響應式push/pop/shift/unshift/splice/sort/reverse
這七個方法,其餘數組方法及數組的使用則沒法檢測到,也沒法監聽數組索引的變化和長度的變動Proxy
的性能比 Promise
還差Proxy
做爲新標準,從長遠來看,JS 引擎會繼續優化 Proxy
Vue 3.0
中放棄了對於IE的支持(覺得 Vue 3.0
中會對不兼容的瀏覽器進行向下兼容,可是通過查看資料和源碼發現尤大壓根沒作兼容)Proxy
全部攔截方法的 Polyfill
方案,有一個 google
編寫的 proxy-polyfill
也只支持了 get/set/apply/construct
四種攔截Decorator
,至關於設計模式中的裝飾器模式。Proxy
和 Decorator
的使用場景,能夠歸納爲:Proxy
的核心做用是控制外界對被代理者內部的訪問,Decorator
的核心做用是加強被裝飾者的功能。