雙向綁定Proxy VS Object.defineProperty


Vue3.0的雙向綁定將使用Proxy代替Object.defineProperty,據尤大說,速度提升了1倍。

本文我們來探討一下Proxy對比Object.defineProperty究竟有哪些優劣呢?

 

首先介紹一下什么是Proxy?

Proxy在ES6規范中被正式發布,Proxy可以理解成在目標對象之前架設一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。

Proxy語法:

ES6原生提供Proxy構造函數,用來生成Proxy實例

var proxy = new Proxy(target,handler);

Proxy接受兩個參數:

target:要代理目標對象

handler: 處理函數,該函數將攔截對應的操作

下面是 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提供兼容。 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM