1. 程式人生 > 其它 >js的Proxy代理物件?看完你就會了

js的Proxy代理物件?看完你就會了

什麼是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