Proxy 用於修改某些操做的默認行爲,等同於在語言層面作出修改,因此屬於一種『元編程』即對編程語言進行編程。
Proxy 是在目標對象以前架設一層『攔截』,外部對對象的訪問,都須要通過該層攔截。所以在攔截中對外界的訪問進行過濾和改寫。
在Es6 中 提供了原生的 Proxy 構造函數,能夠用來生成 Proxy實例。編程
let proxy = new Proxy(target, handler)
Proxy 對象的全部用法,都是上面的形式,不一樣的只是handler參數的寫法。其中new Proxy() 表示生成一個 Proxy實例,target 參數表示全部攔截的目標對象, handler 參數也是一個對象,用來定製攔截行爲。以下:segmentfault
let proxy = new Proxy({}, { get: function(target, property) { return 35 } }) proxy.time // 35 proxy.name // 35 proxy.title // 35
解讀:數組
在上面中,做爲構造函數,Proxy接受兩個參數。第一個參數即所要代理的目標對象,若是沒有 Proxy的介入,操做原來要訪問的就是這個對象。第二個參數是一個配置對象,用來對每一個代理對象的操做,提供具體的函數和攔截操做。上述代碼中有一個 get 函數,用來攔截對目標對象屬性的訪問請求。app
另外,要使 Proxy起做用,必須針對 Proxy 實例進行操做,而不是針對目標對象進行操做。編程語言
若是 handler 沒有設置任何攔截,那就等同於直接通向原對象。以下:函數
let target = {} let handler = {} let proxy = new Proxy(target, handler) proxy.a = 'b' target.a = 'b'
對於上面的例子,咱們能夠講Proxy對象,設置到 object.proxy屬性,從而能夠在object對象上調用。this
let object = {proxy: new Proxy(target, handler)}
Proxy 實例也能夠做爲其餘對象的原型對象。spa
let proxy = new Proxy({}, { get: function(target, property) { retrun 35 } }) let obj = Object.create(proxy) obj.time // 35 另外同一個攔截器,能夠設置多個攔截操做。
經常使用的Proxy支持的攔截操做以下:代理
get 方法用於攔截某個屬性的讀取操做,能夠接受三個參數,依次爲目標對象、屬性名和proxy實例自己,最後一個參數可選。
let p = { name: '李四' } let proxy = new Proxy(p, { get: function(target, property) { if (property in target) { retrun target[property] } else { console.log('報錯') } } }) proxy.name // '李四' proxy.age // '報錯'
注意點code
set 方法用來攔截某個屬性的賦值操做,能夠接受四個參數,依次爲目標對象、屬性名、屬性值和Proxy實例自己,最後一個可選
let v = { set: function(obj, prop, value) { if (prop === 'age') { if(!Number.isInteger(value)) { console.log('報錯') } if(value > 200) { console.log('成功') } obj[prop] = value } } } let p = new Proxy({}, v) p.age = 100 p.age // 100 p.age = 'n' p.age // 報錯
利用set方法,能夠數據綁定,即每當對象發生變化時,會自動更新Dom
若是目標對象自身的某個屬性,不可寫且不可配置,那麼Set 方法將不起做用。
1.4 apply()
apply 方法攔截函數的調用、call 和 apply操做。它能夠接受三個參數,分別時目標對象、目標對象的上下文對象(this)和目標對象的參數數組。
let h = { apply(target, ctx, args) { return Reflect.apply(...arguments) } } let target = function() {return 'haha') let h = { apply: function() { return 'heihei' } } let p = new Proxy(taraget, h) p() // 'heihei'
has 方法用來攔截 HasProperty 操做, 即判斷對象是否具備某個屬性時,這個方法會生效。
has 方法能夠接受兩個參數,分別時目標對象、須要查詢的屬性名。
注意:has 方法攔截的時 HasProperty操做,而不是HasOwnProperty操做,即has 方法不判斷一個屬性是對象自身的屬性,仍是繼承的屬性。
construct 方法用於攔截 new命令,下面是攔截對象的寫法
let h = { construct(target, args, newTarget) { retrun new target(...args) } } target: 目標對象 args: 構造函數的參數對象 newTarget: 創造實例對象時,new命令做用的構造函數
deleteProperty 方法用於攔截 delete 操做,若是這個方法拋出錯誤或者返回false,當前屬性就沒法被delete命令刪除。
雖然 Proxy 能夠代理針對目標對象的訪問,但它不是目標對象的透明代理,即不作任何攔截的狀況下,也沒法保證目標對象的行爲一致。主要緣由就是在Proxy代理的狀況下,目標對象內部的this關鍵字會指向Proxy代理