代理
//es5 代理方式
let obj={}
let newVal=''
Object.defineProperty(obj,'name',{
get(){
console.log('get');
return newVal
},
set(val){
console.log('set');
newVal=val
}
})
obj.name='es' //set
console.log(obj.name); //get es
let obj={}
let p=new Proxy(obj,{})
p.name='hi'
console.log(obj.name); //hi
for(let key in obj){console.log(key);} //name
//es6中使用Reflect.defineProperty 将Object属于语言内部的方法放到Reflect上 更加规范
let obj={}
Object.defineProperty(obj,'name',{})
Reflect.defineProperty(obj,'name',{})
//返回boolean 修改某些Object方法的返回结果,让其变得更合理
// if(Reflect.defineProperty()){}else{}
//让Object操作变成函数行为
console.log('assign' in Object) //true
console.log(Reflect.has(Object,'assign')) //true
//Reflect对象的方法于Proxy对象的方法一一对应
常用拦截方法
- get
拦截对象属性的读取,比如proxy.foo和proxy['foo']
// 判断数组的下标是否有值,有值返回值,没值返回下标
let arr=[7,8,9]
arr=new Proxy(arr,{
get(target,prop){
// console.log(target,prop); //arr[1]->target [7,8,9],prop '1'
return prop in target ? target[prop] : 'error'
}
})
console.log(arr[1]); //8
console.log(arr[3]); //error
//字典翻译,输入hello返回你好,输入字典没有的返回原值
let dict={
'hello':'你好',
'world':'世界'
}
dict=new Proxy(dict,{
get(target,prop){
return prop in target ? target[prop] : prop
}
})
console.log(dict['world']); //世界
console.log(dict['good']); //good
- set
拦截对象属性的设置,返回一个布尔值,比如proxy.foo=v或proxy['foo']=v
//限制arr内限制只能设置number值,其他值返回错误
let arr=[]
arr=new Proxy(arr,{
set(target,prop,val){
if(typeof val==='number'){
target[prop]=val
return true
}else{
return false
}
}
})
arr.push(1)
console.log(arr[0]); //1
arr.push(2)
console.log(arr[1],arr.length); //2 2
- has
拦截propKey in proxy的操作,返回一个布尔值
//判断是否在范围内,返回布尔型值
let range={
start:1,
end:5
}
range=new Proxy(range,{
has(target,prop){
return prop>=target.start && prop<=target.end
}
})
console.log(2 in range); //true
console.log(9 in range); //false
- ownKeys
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组
//使用Symbol例子
let obj={
name:'daji',
[Symbol('es')]:'es'
}
console.log(Object.getOwnPropertyNames(obj)) //['name']
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(es)]
console.log(Object.keys(obj)) //['name']
for(let key in obj){
console.log(key); //name
}
//不想被遍历出私有属性以下划线开头的 _parssword 使用ownKeys
let userinfo={
name:'daji',
age:18,
_password:'***'
}
userinfo=new Proxy(userinfo,{
ownKeys(target){
return Object.keys(target).filter(key=>!key.startsWith('_'))
}
})
for(let key in userinfo){
console.log(key); //name age
}
console.log(Object.keys(userinfo)); //['name','age']
- deleteProperty
拦截delete proxy[proKey] 返回一个布尔值
//阻止对私有属性的任何访问 _password
let user={
name:'daji',
age:18,
_password:'***'
}
user=new Proxy(user,{
get(target,prop){ //不允许获取
if(prop.startsWith('_')){
throw new Error('不可访问')
}else{
return target[prop]
//return Reflect.get(target,prop)
}
},
set(target,prop,val){ //不允许设置 返回布尔型值
if(prop.startsWith('_')){
throw new Error('不可访问')
}else{
target[prop]=val //Reflect.set(target,prop,val)
return true
}
},
deleteProperty(target,prop){ //不允许删除 返回布尔型值
if(prop.startsWith('_')){
throw new Error('不可删除')
}else{
delete target[prop] //Reflect.delete(target,prop)
return true
}
},
ownKeys(target){ //不允许遍历
return Object.keys(target).filter(key=>!key.startsWith('_'))
//return Reflect.ownKeys(target).filter(key=>!key.startsWith('_'))
}
})
//get 测试
// console.log(user.age); //18
// console.log(user._password); //报错Error: 不可访问
//set 测试
user.age=100
console.log(user.age); //100
//捕获异常写法
try{
user._password='xxx'
}catch(e){
console.log(e.message); //不可访问
}
//删除 测试
try{
delete user._password
}catch(e){
console.log(e.message); //不可删除
}
//遍历 测试
for(let key in user){
console.log(key); //name age
}
- apply
拦截函数调用,apply和call操作
let sum=(...args)=>{
let num=0
args.forEach(item=>{
num+=item
})
return num
}
sum=new Proxy(sum,{
apply(target,ctx,args){ //ctx上下文
return target(...args)*2 //return Reflect.apply(target,target,[...args])*2
}
})
console.log(sum(1,2)); //6
console.log(sum.call(null,1,2,3)); //null不改变指向 12
console.log(sum.apply(null,[1,2,3])); //12
- construct
construct 拦截new 返回一个对象
let User=class{
constructor(name){
this.name=name
}
}
User=new Proxy(User,{
construct(target,args,newTarget){ //args构造函数的参数
return new target(...args)
}
})
console.log(new User('hi')); // User {name: "hi"}