JavaScript的Proxy代理对象,看完你就会了

web前端开发

共 2661字,需浏览 6分钟

 ·

2021-06-16 12:15


什么是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}// 捕获器trapvar 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 = 97pObj.wallet = 94pObj.wallet = 91pObj.wallet = 88pObj.wallet = 85
console.log(obj.wallet) // 85console.log(consume) // 5

如何取消代理

假如某一天,你实现了财务自由,不需要再精打细算记录每一笔消费了,你可能就需要取消此前的代理,代码很简单,往下看:

var consume = 0var 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.proxyvar prevoke = tmpObj.revoke
// 使用代理对象进行消费记账pObj.wallet = 97pObj.wallet = 94pObj.wallet = 91
// 某一天,我们实现了一个小目标pObj.wallet = 100000000// 我们不需要记账了,我们需要取消创建的代理prevoke() // 执行prevoke即可,就是这么简单 哦耶~
pObj.wallet = 99999997 // TypeError 报错啦 (代理取消之后就不能使用了哟!)

代理在后模式

前面的示例都是先执行代理捕获器中的业务逻辑,最后再通过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 someonegreeter.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

本文完~

学习更多技能

请点击下方公众号

浏览 36
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报