js的Proxy代理物件?看完你就會了
阿新 • • 發佈:2021-06-24
什麼是Proxy代理?
// pOjb就是通過new Proxy建立的代理物件
var pObj = new Proxy(obj, handlers)
為什麼需要代理物件
舉個記賬的例子:
// obj代表我們,wallet屬性指我們錢包,現在我們錢包裡有100元
// consume指消費次數,每次消費加1, 記一筆賬
var obj = {wallet: 100}
var consume = 0
// 這個月,我們喝了五次肥宅快樂水,每次消費我們都記一筆
// 今天消費3元
consume++
obj.wallet = 97
// 今天消費3元
consume++
obj.wallet = 94
// 今天消費3元
consume++
obj.wallet = 91
// 今天消費3元
consume++
obj.wallet = 88
// 今天消費3元
consume++
obj.wallet = 85
每次我們修改錢包剩餘金額時,都要執行一次consume++去執行一次記賬的操作。有沒有更簡單的方式,不需要每次都寫上一行程式碼去增加消費次數呢?
答案當然有,它就是Proxy代理物件!使用代理物件,你想對目標物件的屬性操作全部改為對代理物件相同屬性的操作,代理物件提供了對屬性獲取 [[get]] 修改 [[set]] 等操作的攔截,js將這種攔截稱為trap(捕捉器)。
通過捕捉器,我們就可以捕獲到 程式碼中對屬性的操作時機,讓我們能夠先執行我們自定義的業務邏輯程式碼。因為我們對目標物件的屬性操作改為了對代理物件相同的屬性操作,所以我們在最後需要通過Reflact執行目標物件的原始操作。
var consume = 0
// 目標物件
var obj = {wallet: 100}
// 捕獲器trap
var handlers = {
set(target, key, val) {
// target 目標物件
// key 代理物件要修改的屬性
// 記錄一筆消費
consume++
// 通過Reflact物件觸發原始目標物件的屬性操作
// 相當於執行 target[key] = val
Reflect.set(target, key, val)
}
}
// 代理物件
var pObj = new Proxy(obj, handlers)
// 將對目標物件obj的屬性wallet操作改為代理物件相同屬性wallet的操作
pObj.wallet = 97
pObj.wallet = 94
pObj.wallet = 91
pObj.wallet = 88
pObj.wallet = 85
console.log(obj.wallet) // 85
console.log(consume) // 5
如何取消代理
假如某一天,你實現了財務自由,不需要再精打細算記錄每一筆消費了,你可能就需要取消此前的代理,程式碼很簡單,往下看:
var consume = 0
var obj = {wallet: 100}
var handlers = {
set(target, key, val) {
consume++
Reflect.set(target, key, val)
}
}
// 使用Proxy.revocable建立代理
var tmpObj = Proxy.revocable(obj, handlers)
var pObj = tmpObj.proxy
var prevoke = tmpObj.revoke
// 使用代理物件進行消費記賬
pObj.wallet = 97
pObj.wallet = 94
pObj.wallet = 91
// 某一天,我們實現了一個小目標
pObj.wallet = 100000000
// 我們不需要記賬了,我們需要取消建立的代理
prevoke() // 執行prevoke即可,就是這麼簡單 哦耶~
pObj.wallet = 99999997 // TypeError 報錯啦 (代理取消之後就不能使用了喲!)
https://www.98891.com/article-14-1.html
代理在後模式
前面的示例都是先執行代理捕獲器中的業務邏輯,最後再通過Reflect執行目標物件的屬性操作,這種捕獲程式碼操作在前,目標物件操作在後的模式稱為“代理在先”模式,有在先,當然就有在後模式。
當然這裡的“代理在後”模式並不是先使用Reflect物件觸發目標物件屬性操作,在執行捕獲器中的其他操作程式碼。而是指代理作為目標物件的一種補充,我們仍然操作的是目標物件,只是當某些操作在目標物件上無法實現時,才使用代理物件。
等會,當某些操作目標物件無法提供時,js會向目標物件的原型prototype上進行查詢,所以“代理在後”模式是對目標物件的原型進行代理!
var handlers = {
get(target, key, context) {
return function () {
context.speak(key + '!')
}
}
}
var catchall = new Proxy({}, handlers)
var greeter = {
speak(who = 'someone') {
console.log('hello ', who)
}
}
// 將catchall設定為greeter的原型
Object.setPrototypeOf(greeter, catchall)
greeter.speak() // hello someone
greeter.speak('world') // hello world
// 執行greater上不存在的方法
greeter.everyone() // hello everyone!
Reflect
Reflect物件用來觸發目標物件執行相應的操作,就是這麼簡單!
Reflect.get(target, key, context) // 等價於 target[key]
Reflect.set(target, key, val) // 等價於 target[key] = val