在谈到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++
每次我们在修改钱包剩余金额时,都要执行一次con++去执行一次记账的操作,那么有没有更简单的方式,可以让我们不需要每次都写上一行代码来增加消费的次数呢?
答案当然是有的,它就是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(consume) // 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 // 会显示报错 (代理取消就不能再使用)