正如Proxy的英译"代理"所示,Proxy是ES6为了操作对象引入的API。它不直接作用在对象上,而是作为一种媒介,如果需要操作对象的话,需要经过这个媒介的同意。
使用方式
/* @params
** target:⽤Proxy包装的⽬标对象
** handler:⼀个对象,对代理对象进⾏拦截操作的函数,如set、get*/
let p = newProxy(target,handler)
常用方法
get读取
set设置
has判断key是否存在
deleteProperty拦截delete
ownKeys拦截Object.keys等
{
proxy
let account = {
id:9999,
name:'admin',
phone:'12345678909',
create_time:'2021-10-13',
_private:'demo'
}
let accountProxy = new Proxy(account,{
// 拦截读取
// 手机号中间四位变成****;创建时间改为2021-10-00
get:function(target,key){
switch(key){
case 'phone':
return target[key].substring(0,3)+'****'+target[key].substring(7)
break;
case 'create_time':
return target[key].replace('2021-10-13','2021-10-00')
break;
default:
return target[key]
break;
}
},
// 拦截设置
// id不可更改
set:function(target,key,value){
if(key === 'id'){
return target[key]
}else{
return target[key] = value
}
},
// 判断key是否存在
has:function(target,key){
if(key in target){
console.log(`${key}:${target[key]}`);
return true
}else{
console.log('没有这个属性');
return false
}
},
// 拦截delete
// _开头的为私有属性,不可删除
deleteProperty:function(target,key){
if(key.indexOf('_')===0){
console.warn('私有属性,不可删除');
return true //代表该方法执行成功,如果返回false代表方法执行失败
}else{
delete target[key]
return true
}
},
// 拦截Object.key()
// 如果是id或者是私有属性就不输出
ownKeys(target){
return Object.keys(target).filter(item=>{
return item !== 'id' && item.indexOf('_') !== 0
})
}
})
console.log('拦截读取',accountProxy.phone,accountProxy.create_time);
accountProxy.id = 1234;
accountProxy.name = 'xiaoming'
console.log('拦截设置',accountProxy.id,accountProxy.name);
console.log('拦截has','gender' in accountProxy);
console.log('拦截has','name' in accountProxy);
console.log('拦截delete',delete accountProxy['_private']);
console.log('拦截delete',delete accountProxy['name']);
console.log(accountProxy);
console.log(account);
console.log('拦截Object.keys()方法',Object.keys(accountProxy));
Reflect
与Proxy相同,ES6引入Reflect也是用来操作对象的,它将对象里一些明显属于语言内部的方法移植到Reflect对象上,它对某些方法的返回结果进行了修改,使其更合理,并且使用函数的方式实现了Object的命令式操作
Reflect.set(target, propertyKey, value[, receiver])//如果遇到 setter,receiver则为setter调用时的this值
Reflect.has(obj, name)是 name in obj 指令的函数化,用于判断对象中是否有某一个属性, 返回值为布尔值
// Reflect
let obj = {
name:'xiaoming',
age:19,
gender:'man',
hobbies:'xxxxxxxx'
}
console.log('hobbies',Reflect.get(obj,'hobbies'));
Reflect.set(obj,'name','Jim')
console.log('obj',obj);
console.log('has',Reflect.has(obj,'name'));
let exam = {
name: 'Tom',
age: 19,
get info() {
return this.name + this.age
}
}
console.log(Reflect.get(exam, 'info'));//Tom19
console.log(Reflect.get(exam, 'name'));//Tom
// 当target对象中存在get方法,如果有receiver则this指向receiver
let receiver = {
name:'Jim',
age:20
}
console.log(Reflect.get(exam,'info',receiver));//Jim20
使用Proxy与Reflect实现简单的双向数据绑定
获取dom对象
设置代理对象
配置代理选项
添加事件
实现双向数据绑定
// 获取dom元素
const txt = document.getElementById('txt')//span
const inp = document.querySelector('#inp');//input
// 初始化代理对象
const obj = {}
// 代理选项
const handle={
get(target,key){
console.log('get');
return Reflect.get(target,key)
},
set(target,key,value){
if(key === 'text'){
inp.value = inp.value === value?inp.value:value
txt.innerHTML = value
}
return Reflect.set(target,key,value)//更新OBJ
}
}
let objProxy = new Proxy(obj,handle)
inp.addEventListener('keyup',function(e){
objProxy.text = e.target.value
console.log(obj);
})
objProxy.text = 1234567890