雙向綁定Proxy VS Object.defineProperty

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 種。雙向綁定

  • get(target, propKey, receiver):攔截對象屬性的讀取,好比proxy.fooproxy['foo']
  • set(target, propKey, value, receiver):攔截對象屬性的設置,好比proxy.foo = vproxy['foo'] = v,返回一個布爾值。
  • has(target, propKey):攔截propKey in proxy的操做,返回一個布爾值。
  • deleteProperty(target, propKey):攔截delete proxy[propKey]的操做,返回一個布爾值。
  • ownKeys(target):攔截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循環,返回一個數組。該方法返回目標對象全部自身的屬性的屬性名,而Object.keys()的返回結果僅包括目標對象自身的可遍歷屬性。
  • getOwnPropertyDescriptor(target, propKey):攔截Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對象。
  • defineProperty(target, propKey, propDesc):攔截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一個布爾值。
  • preventExtensions(target):攔截Object.preventExtensions(proxy),返回一個布爾值。
  • getPrototypeOf(target):攔截Object.getPrototypeOf(proxy),返回一個對象。
  • isExtensible(target):攔截Object.isExtensible(proxy),返回一個布爾值。
  • setPrototypeOf(target, proto):攔截Object.setPrototypeOf(proxy, proto),返回一個布爾值。若是目標對象是函數,那麼還有兩種額外操做能夠攔截。
  • apply(target, object, args):攔截 Proxy 實例做爲函數調用的操做,好比proxy(...args)proxy.call(object, ...args)proxy.apply(...)
  • construct(target, args):攔截 Proxy 實例做爲構造函數調用的操做,好比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提供兼容。 

相關文章
相關標籤/搜索