一: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
物件上。現階段,某些方法同時在Object
和Reflect
物件上部署,未來的新方法將只部署在Reflect
物件上。也就是說,從Reflect
物件上可以拿到語言內部的方法。
2、修改某些Object
方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)
在無法定義屬性時,會丟擲一個錯誤,而Reflect.defineProperty(obj, name, desc)
則會返回false
。
3、讓Object
操作都變成函式行為。某些Object
操作是命令式,比如name in obj
和delete 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
方法將值賦值給物件的屬性,確保完成原有的行為,然後再部署額外的功能。