在此暴骂六个月之前的我,对象代理这好的东西居然不用。。。。。。。。
一、咱就先聊聊对象代理Proxy的作用
为何称作为代理呢?那就说明我们可以自定义设置对象某些命令执行的原生方法,比如当我们没有为对象套一层代理,执行objectName.attr时,就会默认执行对象原生方法函数get();然而当我们在对象声明时套层代理时,那就说明我们不会直接通过对象某些执行命令的原生方法来操作对象,而是先检测代理是否有其命令对应声明的方法,若没有再执行原生的命令执行方法。
二、优点
解决了批量对对象某些属性的数据操作
比如场景:当我要使用对象中某个属性值时,若属性值为undefined,则取值默认100,下面演示两种做法
const obj = {
'first': 'first',
'second': undefined,
}
// 未加对象代理
const getValue_unProxy = (obj, attr) => obj[attr] === undefined ? 100 : obj[attr]
console.log(getValue_unProxy(obj, 'second')) // 100
// 加对象代理
const hander = {
get(target, property, receiver) {
return target[property] === undefined ? 100 : target[property]
}
}
const proxyObj = new Proxy(obj, hander)
const getValue_proxy = (obj, attr) => obj[attr]
console.log(getValue_proxy(proxyObj, 'second')) // 100
分析:
可能咋眼一看,可能有些同学觉得是不加对象代理比较好,又不麻烦,取值时只要加一个判断而已啦;加了对象代理还要重新声明一个变量,还要自己写一个方法函数,好麻烦啊。 可是如果这个对象要在项目中多模块中都会使用,且也是这个规则,那你岂不是用一个就要加一个判断?爱偷懒的程序员永远不会这么傻憨憨,那就有同学可能会在传入这个对象的数据源【比如:获取这个对象的某个接口】对这个对象进行内部改值处理了,想想如果这么做了,我就不知道那些属性原先属性值为undefined,而那些属性值本就为100【根据本人工作经验,不到万不得已,不要改动最初数据源的值,不然会使数据源产生可变性,数据的不可控制性】,这就很可怕了。既想一劳永逸【只需要对这个对象配置ok,之后只要使用这个对象就行,而不是用一处就加一个操作处理】,又想不改动源数据值,那么对象代理Proxy
就是个很好的方法【方正对对象加一层自定义的操作中间件不是挺好的嘛,又没有对其有什么副作用,加了不吃亏,加了不上当,舒舒服服美滋滋~~】。
三、其几种常用方法及注意事项
1、get()【对应代理对象取属性值操作命令】
const hander = {
// 对应取属性值命令
get(target, property, receiver) {
return target[property] === undefined ? '还没有定义哟' : target[property]
},
}
const spiderObj = new Proxy({}, hander)
spiderObj.mouse = undefined
console.log(spiderObj.mouse) // 还没有定义哟
console.log(spiderObj) // Proxy {mouse: undefined}
注意:当属性存在属性特性configurable: false, value: undefined,
时,则取其属性值时会报错
Uncaught TypeError: 'get' on proxy: property 'mouse' is a read-only and non-configurable data property on the proxy target
2、set()【对应代理对象设置属性值操作命令】
const hander = {
//对应设置属性值命令
set(target, property, value) {
const intValue = parseInt(value)
if (property === 'leg') {
if (intValue > 0) {
return Reflect.set(...arguments)
}
if (intValue === 0) {
console.log('正常蜘蛛不应该没有腿哟')
}
if (intValue < 0) {
console.log('正常蜘蛛腿数量不应该小于零哟')
}
return true // 表示设置成功
}
else {
return Reflect.set(...arguments) // Reflect.set(...arguments)返回回一个布尔值
}
}
}
const spiderObj = new Proxy({}, hander)
spiderObj.leg = 0 // 正常蜘蛛不应该没有腿哟
console.log(spiderObj) // Proxy {}
3、deleteProperty【对应delete proxy[attr]、delete proxy.attr和Reflect.deleteProperty()操作命令】
const hander = {
// 对应删除属性命令
deleteProperty(target, property) {
property === 'hearder' && console.log('蜘蛛没了头会死的哟')
return property === 'hearder' ? false : true
},
}
const spiderObj = new Proxy({
'hearder': 1,
}, hander)
delete spiderObj.hearder // 蜘蛛没了头会死的哟
console.log(spiderObj) // Proxy {hearder: 1}
剩余的就不做过多解释了
上述示例全部:
const hander = {
// 对应取属性值命令
get(target, property, receiver) {
return target[property] === undefined ? '还没有定义哟' : target[property]
},
//对应设置属性值命令
set(target, property, value) {
const intValue = parseInt(value)
if (property === 'leg') {
if (intValue > 0) {
return Reflect.set(...arguments)
}
if (intValue === 0) {
console.log('正常蜘蛛不应该没有腿哟')
}
if (intValue < 0) {
console.log('正常蜘蛛腿数量不应该小于零哟')
}
return true // 表示设置成功
}
else {
return Reflect.set(...arguments) // Reflect.set(...arguments)返回回一个布尔值
}
},
// 对应删除属性命令
deleteProperty(target, property) {
property === 'hearder' && console.log('蜘蛛没了头会死的哟')
return property === 'hearder' ? false : true
}
}
const spiderObj = new Proxy({
'hearder': 1,
}, hander)
spiderObj.mouse = undefined
console.log(spiderObj.mouse) // 还没有定义哟
spiderObj.leg = 0 // 正常蜘蛛不应该没有腿哟
delete spiderObj.hearder // 蜘蛛没了头会死的哟
console.log(spiderObj) // Proxy {hearder: 1, mouse: undefined}
总结:对象代理提供了一种从源头上对对象的各种格式化配置函数,也可以侧面的称之为钩子函数,真心不错,就是以前太毛毛躁躁了,就一眼看过,没留心。