基本认知
在 ES6 标准中新增的一个非常强大的功能是 Proxy,它可以自定义一些常用行为如查找、赋值、枚举、函数调用等。通过 Proxy 这个名称也可以看出来它包含了“代理”的含义,只要有“代理”的诉求都可以考虑使用 Proxy 来实现。
语法:
let p = new Proxy(target, handler)
参数:
参数 |
含义 |
必选 |
target |
用proxy包装的目标对象(可是任何类型的对象,包括原生数组,函数,甚至是另一个代理) |
Y |
handler |
一个对象,其属性是当执行一个操作时定义代理的行为的函数 |
Y |
简单的使用场景:
我们经常读取一个对象的 key-value:
let o = {
name:'xicheng',
age:23
}
let handler = {
get(obj, key) {
return Reflect.has(obj, key) ? obj[key] : ''
}
}
let p = new Proxy(o, handler)
console.log(p.name) //xicheng
console.log(p.xx) //''
这个代码是想表达如果 o 对象有这个 key-value 则直接返回,如果没有一律返回 '',当然这里是自定义,可以根据自己的需要来写适合自己业务的规则。
写操作拦截
场景:指写数据不可写
let o = {
name:'xicheng',
age:23
}
let handler = {
get(obj, key) {
return Reflect.has(obj, key) ? obj[key] : ''
},
set(obj, key ,value) {
return false; //对数据的“写操作”进行了拦截
}
}
let p = new Proxy(o, handler)
console.log(p.name) //xicheng
console.log(p.xx) //''
es5类似锁定写操作:
let 0 = {
name:'xicheng',
age:23
}
for( let [key] of Object.entries(o)){ //es6可以使用Reflect
Object.defineProperty(o,key,{
writable:false;
})
}
相较Proxy来说,这种方法过于死板,是将原数据给直接锁写了.
较验的应用
let o = {
name:'xicheng',
age:23
}
let validator = (obj, key ,value) => {
if(Reflect.has(obj,key)){
if(key == 'price'){
if(value > 300) {
return false;
} else {
obj[key] = value
}
} else {
obj[key] = value
}
} else {
return false
}
}
let handler = {
get(obj, key) {
return obj[key] || ''
},
set:validator
}
let p = new Proxy(o, handler)
监控上报
//监听错误
window.addEventListener('error',(e) => {
console.log(e.message)
//可以加入上报逻辑
},true)
let 0 = {
name:'xicheng',
age:23
}
let validator = (obj, key ,value) => {
if(Reflect.has(obj,key)){
if(key == 'price'){
if(value > 300) {
//规则不满足,则触发错误
throw new TypeError('price exceed 300')
//return false;
} else {
obj[key] = value
}
} else {
obj[key] = value
}
} else {
return false
}
}
let handler = {
get(obj, key) {
return obj[key] || ''
},
set:validator
}
let p = new Proxy(o, handler)
只读随机唯一id
class Component {
//constructor () { //错误方案一
// this.id = Math.random().toString(36).slice(-8)
//}
//get id(){ //错误方案二
// return Math.random().toString(36).slice(-8)
//}
constructor () {
this.proxy = new Proxy({
id:Math.random().toString(36).slice(-8)
},{})
}
get id () {
return this.proxy.id
}
}
let com = new Component()
let com2 = new Component()
for(let i=0 ; i < 10 ; i++) {
console.log(com.id,com2.id)
}
com.id = 'abc'
console.log(com.id,com2.id)
撤消代理
let 0 = {
name:'xicheng',
age:23
}
let handler = {
get(obj, key) {
return Reflect.has(obj, key) ? obj[key] : ''
}
}
let p = Proxy.revocable(o, handler)
console.log(p.proxy.name) //xicheng
console.log(p.proxy.xx) //''
console.log(p) // {proxy:Proxy,revoke:f}
//撤消代理:
p.revoke();
//代理已被撤消
console.log(p.name) // Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoke at eval
一旦 revoke 被调用,proxy 就失效了,这也就起到了“临时”代理的作用