1.Proxy和Reflect
-
Proxy:代理;连接了用户和最真实对象中间一个层;
-
Reflect :反射;反射的Object;
- Proxy对象和Reflect对象的方法是一模一样的;
- var obj = new Proxy(要代理的对象,{实现要代理的东西(方法)});
- var obj2 = Reflect();
- Proxy对象和Reflect对象的方法是一模一样的;
-
Proxy和Reflect的概念
-
Proxy和Reflect的适用场景
2.
{
//供应商,原始对象来存储真实的数据;
//1.有一个类似于供应商的原生数据对象obj;
let obj = {
time:'2017-10-15',
name:'net',
_r:123
};
//创建一个代理商;
//2.通过Proxy新生成一个对象,这个对象是映射Obj的;然后再中间做一些操作;
let monitor = new Proxy(obj,{
//代理了所有对象属性的读取的一个作用;
//(拦截对象属性的读取,拦截和代理是一个意思;)
//拦截代理所有跟读取相关的属性;
get(target,key){
//不管读取什么属性,要把所有属性中值的2017替换成2018
return target[key].replace('2017','2018');
},
//拦截对象设置属性
//不让修改除了name属性以外的属性;
set(target,key,value){
if(key ==='name'){
//把新设置的value赋值给这个对象target也就是obj;
return target[key] = value;
}else{
return target[key];
}
},
//判断当前对象中是不是拥有某个属性;in运算符判断在一个对象中;
//拦截key in object 操作;
has(target,key){
//只暴露name属性,其他的都不暴露;
if(key ==='name'){
return target[key];
}else{
return false;
}
},
//删除,object有个属性通过delete运算符就可以删除那个属性;
//通过代理Proxy拦截这种操作;实现了对delete的代理操作;
deleteProperty(target,key){
//如果是_下划线开头的可以删除,其他的不允许删除;
if(key.indexOf('_')>-1){
delete target[key];
return true;
}else{
return target[key];
}
},
//拦截Object.keys,object.getOwnPropertySymbols,object.getOwnPropertyNames;
ownKeys(target){
//通过Object.keys把原始对象所有的keys都拿出来,在基础上进行过滤;如果是time就不返回;
//过滤掉time这个属性,达到了保护time属性的真实做法;
return Object.keys(target).filter(item=>item!='time');
}
});
//3.用户访问的是monitor,不管用户是读取monitor对象、还是设置monitor对象的属性,
//最终通过Proxy在传给这个obj对象;
//从monitor中读取点(.)后面的属性time;
console.log('get',monitor.time); //get 2018-10-15
monitor.time = '2018';
monitor.name ='abc';
console.log('set',monitor.time,monitor);
//set 2018-10-15 Proxy{time:"2017-10-15",name:"abc",_r:123}
//通过代理欺骗了用户,这就是代理所起的作用;
console.log('has','name' in monitor, 'time' in monitor); //has true false
//delete monitor.time;
//console.log('delete',monitor);
//delete Proxy{time:"2017-10-15",name:"abc",_r:123}
//delete monitor._r;
//console.log('deleter_r',monitor);
//deleter_r Proxy{time:"2017-10-15",name:"abc"}
console.log('ownKeys',Object.keys(monitor));
//ownKeys ["name","_r"] 只返回了name、_r,time被保护起来了;
}
3.Reflect (Proxy对象有的方法Reflect都有,名称和用法一摸一样)
要改变直接操作Object的行为习惯,通过Reflect来取和操作;
{
let obj = {
time:'2017-10-15',
name:'net',
_r:123
};
//用reflect读取这个对象
consoel.log('Reflect get',Reflect.get(obj,'time'));
//Reflect get 2017-10-15
Reflect.set(obj,'name','abc');
console.log(obj);
//Object {time:"2017-10-15",name:"abc",_r:123}
//判断obj是不是有name这个属性;
console.log('has',Reflect.has(obj,'name');
//has true
}
4. 真正的开发中怎么去用这个特性呢?
- 传统做法:如果对某个属性进行限制,在赋值的时候对它进行判断,判断这个类型是不是合适,是不是满足其他条件,然后才允许修改这个对象;
- 通过代理的方式把条件和这个对象(业务逻辑)本身完全隔离开,在后期代码维护中,这个时候要加一个手机号的验证扩展,在这个对象类中增加一个mobile,在personValidators中对应加一个mobile限制;后期代码维护,代码整洁度,健壮性,复用性是非常强的;
{
//开发中对一些数据进行校验:
//比如:年龄不是是满足什么样的条件;手机号--点提交的时候判断数据类型是不是这样的;
//通过用Proxy和Reflect实现一个和业务解耦的校验模块;
//提供代理;
function validator(target,validator){
return new Proxy(target,{
_validator:validator,
set(target,key,value,proxy){
if(target.hasOwnProperty(key)){
let va = this._validator[key];
if(!!va(value)){
return Reflect.set(target,key,value,proxy)
}else{
throw Errow(`不能设置${key}到${value}`);
}
}else{
throw Errow(`${key} 不存在`);
}
}
});
}
//过滤的选择,也就是校验的条件;
const personValidators={
name(val){
return typeof val ==='string';
},
age(val){
return typeof val ==='Number'&& val>18;
},
mobile(val){
}
};
//对象
class Person{
constructor(name,age){
this.name = name;
this.age = age;
this.mobile = '1111';
//构造函数返回了Proxy对象,这个proxy对象拦截了(代理了)Person对象;
//在外边操作,并不是真正的操作Person这个类的实例;而是通过Proxy对象对target
的一个代理,这个target是this,this就是Person的实例,Person类实例以后其实得到
的是一个对Person实例对象代理的proxy对象;
return validator(this,personValidatorss);
}
}
const person = new Person('lilei',30);
console.info(person);
//Proxy{name:"lilei",age:30}
//person.name = 48; //报错不能设置name到48
person.name = 'hanmeimei';
console.info(person); //Proxy{name:"hanmeimei",age:30}
}
网友评论