一、代理Proxy
1.Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
2.Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
3.Proxy在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作(后文会说明,有哪些操作可以拦截),必须通过这层拦截。
let p = new Proxy(target,handler)
用Proxy包装的目标对象
是个配置,一个对象,对代理对象进行拦截操作的函数,如set、get...
3.常用方法
- get读取
{
let account = {
id: 999,
name: 'admin',
phone: '12345678910',
creat_time: '2021-10-05',
_private: 'demo'//假设是私有的,过滤的时候对他进行保护
}
let accountProxy = new Proxy(account, {
//读取的时候进行拦截
//手机号中间四位变****,修改创建时间
//此处的target指的是account
get: function (target, key){
switch (key) {
case 'phone':
return target[key].substring(0, 3) + '****' +target[key].substring(7)
break;
case 'creat_time':
return target[key].replace('2021-10-05', '1991-10-05')
break;
default:
return target[key];
break;
}
})
console.log('拦截读取', accountProxy.phone, accountProxy.creat_time);
}
- set设置
{
let obj = {
id: '111',
name: 'aaa',
phone: '12345678910',
creat_time: '2001-10-22',
_private: 'demo'
}
let objProxy = new Proxy(obj, {
//拦截设置
//id不可更改
set:function(target,key,value){
if(key==='id'){
return target[key]//id不可更改,返回的是原始id对应的值
}
else{
return target[key]=value
}
}
})
objProxy.id='6666'
objProxy.name='bbb'
console.log('拦截设置',objProxy.name,objProxy.id);//bbb 111
}
- has判断key是否存在
{
let obj = {
id: '111',
name: 'aaa',
phone: '12345678910',
creat_time: '2001-10-22',
_private: 'demo'
}
let objProxy = new Proxy(obj, {
//判断key是否存在
has: function (target, key) {
if (key in target) {
console.log(`${key}:${target[key]}`);
return true;
}
else {
console.log('没有这个属性');
return false;
}
}
})
console.log('拦截has', 'gender' in objProxy);//没有这个属性 has false
}
- deleteProperty拦截delete
{
let obj = {
id: '111',
name: 'aaa',
phone: '12345678910',
creat_time: '2001-10-22',
_private: 'demo'
}
let objProxy = new Proxy(obj, {
deleteProperty: function (target, key) {
//拦截delete
//以_开头的某个属性,不可删除,其余的全部都可以删
if (key.indexOf('_') === 0) {
console.warn('私有属性不可删除');
return true//代表的是deleteProperty方法执行的成功还是失败,如果返回false,代表执行方法失败
}
else {
delete target[key]
console.log('删除成功');
return true
}
}
})
console.log('拦截delete', delete objProxy._private);//私有属性不可删除 拦截delete true
console.log('拦截delete', delete objProxy.name);//删除成功 拦截delete true
}
- ownKeys拦截Object.keys等
{
let obj = {
id: '111',
name: 'aaa',
phone: '12345678910',
creat_time: '2001-10-22',
_private: 'demo'
}
let objProxy = new Proxy(obj, {
//拦截Object.key()
//如果属性是id或者是私有属性就不输出
ownKeys(target){
return Object.keys(target).filter(item=>{
return item.indexOf('_')!=0 && item !='id'
})
}
})
console.log('拦截Object.keys()方法', Object.keys(objProxy));//['name', 'phone', 'creat_time']
}
二、反射Reflect
- Reflect对象与Proxy对象一样是ES6为了操作对象引入的新API,它将对象里一些明显属于语言内部的方法移植到Reflect对象上,它对某些方法的返回结果进行了修改,使其更合理,并且使用函数的方式实现了Object的命令式操作。
- Reflect并非一个构造函数,所以不能通过new运算符对其进行调用,或者将Reflect对象作为一个函数来调用。
{
//错误
Reflect()// Reflect is not a function
}
- Reflect对象是一个全局的普通的对象,它所有属性和方法都是静态的。
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
{
let obj = {
name: '拉拉',
age: 11,
gender: 'man',
hobbies: 'sing'
}
//get
console.log('Reflect', Reflect.get(obj, 'name'));//Reflect 拉拉
//set
Reflect.set(obj, 'name', '喜喜')
console.log('Reflect', obj.name);//Reflect 喜喜
//has
console.log('Reflect', Reflect.has(obj, 'name'));//Reflect true
console.log('Reflect', Reflect.has(obj, 'a'));//Reflect false
}
- 当target对象中存在get方法,如果有receiver则this指向receiver
{
let exam = {
name: 'aaa',
age: 12,
get info() {
return this.name + this.age
}
}
console.log(Reflect.get(exam, 'info'));//aaa12
console.log(Reflect.get(exam, 'name'));//aaa
// 当target对象中存在get方法,如果有receiver则this指向receiver
let receiver = {
name: 'bbb',
age: 29
}
console.log(Reflect.get(exam, 'info', receiver));//bbb29
}