Proxy 用於修改某些操做的默認行爲,等同於在語言層面作出修改,因此屬於一種『元編程』即對編程語言進行編程。編程
Proxy 是在目標對象以前架設一層『攔截』,外部對對象的訪問,都須要通過該層攔截。所以在攔截中對外界的訪問進行過濾和改寫。數組
在Es6 中 提供了原生的 Proxy 構造函數,能夠用來生成 Proxy實例。app
let proxy = new Proxy(target, handler)
複製代碼
Proxy 對象的全部用法,都是上面的形式,不一樣的只是handler參數的寫法。其中new Proxy() 表示生成一個 Proxy實例,target 參數表示全部攔截的目標對象, handler 參數也是一個對象,用來定製攔截行爲。以下:編程語言
let proxy = new Proxy({}, {
get: function(target, property) {
return 35
}
})
proxy.time // 35
proxy.name // 35
proxy.title // 35
複製代碼
解讀:函數
在上面中,做爲構造函數,Proxy接受兩個參數。第一個參數即所要代理的目標對象,若是沒有 Proxy的介入,操做原來要訪問的就是這個對象。第二個參數是一個配置對象,用來對每一個代理對象的操做,提供具體的函數和攔截操做。上述代碼中有一個 get 函數,用來攔截對目標對象屬性的訪問請求。this
另外,要使 Proxy起做用,必須針對 Proxy 實例進行操做,而不是針對目標對象進行操做。spa
若是 handler 沒有設置任何攔截,那就等同於直接通向原對象。以下:代理
let target = {}
let handler = {}
let proxy = new Proxy(target, handler)
proxy.a = 'b'
target.a = 'b'
複製代碼
對於上面的例子,咱們能夠講Proxy對象,設置到 object.proxy屬性,從而能夠在object對象上調用。code
let object = {proxy: new Proxy(target, handler)}
複製代碼
Proxy 實例也能夠做爲其餘對象的原型對象。對象
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 // '報錯'
複製代碼
注意點
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 方法將不起做用。
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代理