ES6的Proxy和Reflect

Jsp發表於2019-03-04

一:Proxy

Proxy 用於修改某些操作的預設行為,等同於在語言層面做出修改,所以屬於一種“超程式設計”(meta programming),即對程式語言進行程式設計。

Proxy 可以理解成,在目標物件之前架設一層“攔截”,外界對該物件的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這裡表示由它來“代理”某些操作,可以譯為“代理器”。

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});
複製程式碼

上面程式碼對一個空物件架設了一層攔截,重定義了屬性的讀取(get)和設定(set)行為。這裡暫時先不解釋具體的語法,只看執行結果。對設定了攔截行為的物件obj,去讀寫它的屬性,就會得到下面的結果。

obj.count = 1
//  setting count!
++obj.count
//  getting count!
//  setting count!
//  2複製程式碼

ES6 原生提供 Proxy 建構函式,用來生成 Proxy 例項。

var proxy = new Proxy(target, handler);複製程式碼

Proxy 物件的所有用法,都是上面這種形式,不同的只是handler引數的寫法。其中,new Proxy()表示生成一個Proxy例項,target參數列示所要攔截的目標物件,handler引數也是一個物件,用來定製攔截行為。

var proxy = new Proxy({}, {
  get: function(target, property) {
    return 35;
  }
});

proxy.time // 35
proxy.name // 35
proxy.title // 35複製程式碼

二:Reflect

1、將Object物件的一些明顯屬於語言內部的方法(比如Object.defineProperty),放到Reflect物件上。現階段,某些方法同時在ObjectReflect物件上部署,未來的新方法將只部署在Reflect物件上。也就是說,從Reflect物件上可以拿到語言內部的方法。

2、修改某些Object方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會丟擲一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false

3、讓Object操作都變成函式行為。某些Object操作是命令式,比如name in objdelete obj[name],而Reflect.has(obj, name)Reflect.deleteProperty(obj, name)讓它們變成了函式行為。

4、Reflect物件的方法與Proxy物件的方法一一對應,只要是Proxy物件的方法,就能在Reflect物件上找到對應的方法。這就讓Proxy物件可以方便地呼叫對應的Reflect方法,完成預設行為,作為修改行為的基礎。也就是說,不管Proxy怎麼修改預設行為,你總可以在Reflect上獲取預設行為。

Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target,name, value, receiver);
    if (success) {
      log(`property ` + name + ` on ` + target + ` set to ` + value);
    }
    return success;
  }
});

複製程式碼

上面程式碼中,Proxy方法攔截target物件的屬性賦值行為。它採用Reflect.set方法將值賦值給物件的屬性,確保完成原有的行為,然後再部署額外的功能。

相關文章