js的捕捉器---Proxy代理对象

2021-07-12 17:12发布

在谈到js的是trap的时候,我们首先要了解一下什么是Proxy代理?Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。[来源于MDN的说明]

简单的举个例子:

var p = new Proxy(our, handlers);
// p就是通过new Proxy创建的代理对象

那我们为什么会需要代理呢?就像是我们生活中的每一次次的消费之后的记账。

// our代表我们,wallet代表着是我们手里的钱包,假设说现在我们手里的钱包里有200元
// con指我们积累的消费次数,每次消费加1, 记下一笔账
var our = {wallet: 200}
var con = 0

// 假设说在当前的这个月中,我们一共喝了五次透心凉心飞扬,每次消费我们都需要记一笔

// 今天消费3元
con++
our.wallet = 197

// 今天消费3元
con++
our.wallet = 194

// 今天消费3元
con++
our.wallet = 191

// 今天消费3元
con++
our.wallet = 188

// 今天消费3元
con++
our.wallet = 185

每次我们在修改钱包里面的剩余金额时,都要执行一次con++,来执行一次记账的操作。那在这里面有没有更简单的方式,使得我们不需要每次都写上一行代码来增加消费次数呢?

答案是当然的,它就是Proxy代理对象。使用Proxy代理对象,假设你想对目标对象的属性操作全部都改为对代理对象的相同属性操作,那么在代理对象中提供了一种对属性的获取 [[get]] 和修改 [[set]] 等操作的拦截,在js中将这种的拦截称之为捕捉器。

通过捕捉器,我们就可以捕获到 代码中对属性的操作时机,让我们能够先执行我们自定义的业务逻辑代码。

因为我们对目标对象的属性操作改为了对代理对象相同的属性操作,所以我们在最后需要通过Reflact执行目标对象的原始操作。

var con = 0
// 目标对象
var our = {wallet: 200}
// 捕获器trap
var handlers = {
set(target, key, val) {
// target 目标对象
// key 代理对象要修改的属性

// 记录一笔消费
con++
// 通过Reflact对象触发原始目标对象的属性操作
// 相当于执行 target[key] = val
Reflect.set(target, key, val)
}
}
// 代理对象
var p = new Proxy(our, handlers)
// 将对目标对象our的属性wallet操作改为代理对象相同属性wallet的操作
p.wallet = 197
p.wallet = 194
p.wallet = 191
p.wallet = 188
p.wallet = 185

console.log(our.wallet) // 185
console.log(con) // 5

如何取消代理?
假如某一天,我们实现了财务自由,不需要再记录每一笔消费的时候,可能就需要取消此前的代理,那应该如何操作呢?代码如下:

var con = 0
var our = {wallet:  200}
var handlers = {
set(target, key, val) {
con++
Reflect.set(target, key, val)
}
}

// 使用Proxy.revocable创建代理
var t = Proxy.revocable(our, handlers)
var p = t.proxy
var prevoke = t.revoke

// 使用代理对象进行消费记账
p.wallet = 197
p.wallet = 194
p.wallet = 191

// 某一天,我们实现了一个小目标
p.wallet = 100000000
// 我们不需要记账了,我们需要取消创建的代理
prevoke() // 执行prevoke即可

p.wallet = 99999997 // 会直接报错,原因是因为代理取消之后就不能再继续使用