Vue3.0的雙向綁定將使用Proxy代替Object.defineProperty,據尤大說,速度提高了1倍。javascript
本文咱們來探討一下Proxy對比Object.defineProperty究竟有哪些優劣呢?java
首先介紹一下什麼是Proxy?數組
Proxy在ES6規範中被正式發佈,Proxy能夠理解成在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。緩存
Proxy語法:app
ES6原生提供Proxy構造函數,用來生成Proxy實例函數
var proxy = new Proxy(target,handler);
Proxy接受兩個參數:this
target:要代理目標對象spa
handler: 處理函數,該函數將攔截對應的操做prototype
下面是 Proxy 支持的攔截操做一覽,一共 13 種。雙向綁定
proxy.foo
和proxy['foo']
。proxy.foo = v
或proxy['foo'] = v
,返回一個布爾值。propKey in proxy
的操做,返回一個布爾值。delete proxy[propKey]
的操做,返回一個布爾值。Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循環,返回一個數組。該方法返回目標對象全部自身的屬性的屬性名,而Object.keys()
的返回結果僅包括目標對象自身的可遍歷屬性。Object.getOwnPropertyDescriptor(proxy, propKey)
,返回屬性的描述對象。Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一個布爾值。Object.preventExtensions(proxy)
,返回一個布爾值。Object.getPrototypeOf(proxy)
,返回一個對象。Object.isExtensible(proxy)
,返回一個布爾值。Object.setPrototypeOf(proxy, proto)
,返回一個布爾值。若是目標對象是函數,那麼還有兩種額外操做能夠攔截。proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。new proxy(...args)
。下面介紹兩個經常使用的攔截方法:get方法和set方法。
//get方法用於攔截某個屬性的讀取操做 //接受三個參數,依次爲目標對象、屬性名和Proxy實例自己,最後一個參數可選 //set方法用於攔截某個屬性的賦值操做 //接受四個參數,一次爲目標對象、屬性名、屬性值和Proxy實例自己,最後一個參數可選 var person = { name:'Jack', age:20 }; var handler = { get(target,key){ if(key in target){ console.log(`${key}被讀取`); return target[key] }else{ throw new ReferenceError(`Property ${key} does not exist`) } }, set(target,key,value){ console.log(`${key}被設置爲${value}`) target[key] = value } }; let instance = new Proxy(person,handler); instance.name //name被讀取 instance.age = 25 //age被設置爲25
Object.defineProperty缺點:
1. 對數組的支持很差,沒法監聽到數組的變化,在Vue官方文檔說明了能夠監聽到數組的變更,但只限於push、pop、shift、unshift、splice、sort、reverse方法。其實是他們對這幾種方法進行了重寫。
var arrayProto = Array.prototype; var arrayMethods = Object.create(arrayProto); [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ].forEach(function(item){ Object.defineProperty(arrayMethods,item,{ value:function mutator(){ //緩存原生方法,以後調用 console.log('array被訪問'); var original = arrayProto[item] var args = Array.from(arguments) original.apply(this,args) // console.log(this); }, }) })
2.Object.defineProperty監聽的是對象的屬性,當一個對象爲深層嵌套的時候,必須進行遞歸遍歷,比較麻煩。
Proxy對比Object.defineProperty:
優勢:
1. Proxy能夠劫持整個對象,這樣以來操做便利程度遠遠優於Object.defineProperty。
2. Proxy能夠直接監聽數組的變化,無需進行數組方法重寫。
var arr = [1,2,3,4]; var instance = new Proxy(arr,{ get(target,key){ console.log('數組被讀取') return Reflect.get(target,key) }, set(target,key,val){ console.log('監聽到數組更新') return Reflect.set(target,key,val) } }) instance[0] = 5 //監聽到數組更新 instance.push(6) //數組被讀取 監聽到數組更新
3. Proxy支持13種攔截操做,是Object.defineProperty不具有的。
缺點:Proxy的兼容性不是太好,不兼容IE,且沒法經過polyfill提供兼容。