一、引言
想象这样一个场景:银行中有一个保险柜,其中存放了100枚金币和5颗钻石,我们用safe对象来表示:
// 保险柜对象
const safe = {
gold: 100, // 100枚金币
diamond: 5, // 5颗钻石
}
然而,由于保险柜密码被多名员工掌握,任何人都能直接操作保险柜内的物品:
safe.gold -= 50 // 被偷走50个金币
safe.diamond -= 3 // 被偷走3颗钻石
这导致库存数据频繁异常,却无法追溯操作记录和责任人。银行行长为此头疼不已,直到引入了一台智能机器人代理系统—— 所有对保险柜的操作必须通过机器人完成,机器人会根据预设规则校验权限、验证操作合法性,并记录下全程日志。
下面请你带入该场景,我和一起探讨框架响应式基础—— Proxy。
二、什么是Proxy?
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义
我们可以将 Proxy 形象化为银行行长引入的 「智能机器人代理系统」。当使用 new Proxy(target, handler) 代理一个对象时(类比为用机器人系统接管保险柜),Proxy 会在对象的基础操作层插入一层「透明拦截器」,自动拦截并处理该操作。
首先我们需要创建一个对象的代理:
// 保险柜对象
const safe = {
gold: 100, // 100枚金币
diamond: 5, // 5颗钻石
}
// 创建 safe 对象的代理
const safeProxy = new Proxy(safe, handle)
1、get 读取拦截
这样银行家的智能机器人代理系统就有了个大概样子。但是我们现在还没有给这个系统添加规则,告诉它什么时候应该拦截,也就是补全上面代码中的 handle对象。
const handle = {
get: function(target, prop) {
console.log(`${prop}属性被读取!`)
},
}
在上面代码中,我们在 handle 对象中添加 get 方法,该方法在对象的属性被读取时调用(员工取出物品时执行),该函数接受三个参数:
- target: 被代理对象,这里指safe(保险柜)
- prop: 被读取的属性名
- receiver: 暂不介绍
现在我们的操作都要经过智能机器人代理系统哦~
console.log(safeProxy.gold)
// gold 属性被读取
// undefined
可以看到,当我们试图读取 gold 属性的时候,打印 gold 属性被调用,可见拦截器 get 确实拦截到了外界对对象属性的读取操作。
但是为什么当我们打印的代码会显示 undefined 呢?原来 get 拦截器除了拦截读取操作外,还需要决定返回值(返回给正在读取的对象什么值)。如果我们放行本次操作可以这样更改:
const handle = {
get: function(target, prop) {
console.log(`${prop}属性被读取!`)
return target[prop] // 将对象的值返回给读取者
},
}
这样我们的打印语句就可以正常打印了。
现在银行家想更改规则,由于金币比较多,所以允许员工获取,但是钻石数量少,所以当员工获取时需要返回 ‘diamond not allowed’ 的字样,你知道如何修改代码了吗?
// 保险柜对象
const safe = {
gold: 100, // 100枚金币
diamond: 5, // 5颗钻石
}
const handle = {
get: function(target, prop) {
if (prop === 'gold') {
return target[prop]
} else if (prop === 'diamond') {
return 'diamond not allowed'
}
return '无此属性'
},
}
// 创建 safe 对象的代理
const safeProxy = new Proxy(safe, handle)
console.log(safeProxy.gold) // 100
console.log(safeProxy.diamond) // diamond not allowed
console.log(safeProxy.lalala) // 无此属性
2、set 设置拦截
回到最初的场景,当员工前来存钱的时候,也需要经过该系统,此时也必须有一个设置拦截规则来对员工的操作进行拦截和校验。我们需要在 handle对象中添加 set函数来处理值变更时的拦截逻辑:
const handle = {
get: // ... 逻辑忽略
set: function(target, prop, value, receiver) {
return true // 当我们 return true 表示允许本次修改
return false // 当我们 return false 表示拦截这次修改
}
}
该函数接受四个参数:
- target: 被代理对象,这里指safe(保险柜)
- prop: 被读取的属性名
- value: 更改后的值
- receiver: 暂不介绍
如果银行家希望金币的数量不低于50枚,钻石不低于3颗以防库存不足,这我们该怎么实现呢?
// 保险柜对象
const safe = {
gold: 100, // 100枚金币
diamond: 5, // 5颗钻石
}
const handle = {
set: function(target, prop, value) {
if (prop === 'gold') {
if (value < 50) return false
target[prop] = value
return true
} else if (prop === 'diamond') {
if (value < 3) return false
target[prop] = value
return true
}
}
}
// 创建 safe 对象的代理
const safeProxy = new Proxy(safe, handle)
safeProxy.gold -= 10
console.log(safeProxy.gold) // 90
safeProxy.gold -= 50
console.log(safeProxy.gold) // 90 因为 90 -50 = 40 < 50 更改被拦截
三、总结
Proxy 是对象的智能代理,通过拦截读写操作可以实现权限控制、数据校验,避免直接操作对象导致的安全问题和追溯问题。
3040

被折叠的 条评论
为什么被折叠?



