Proxy代理

代理
  • ES5 代理方式
//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
  • ES6 Proxy
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
//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"}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 什么是Proxy代理 ES6 让开发者能进一步接近 JS 引擎的能力,这些能力原先只存在于内置对象上。语言通过代理...
    27亿光年中的小小尘埃阅读 501评论 0 1
  • 一、概述 Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta pr...
    了凡和纤风阅读 289评论 0 1
  • 来自深入理解ES6第十二章,由于最近业务中经常用到,记录一下 这里内容都太学术了,有一篇简单介绍Proxy作用的文...
    NowhereToRun阅读 1,043评论 0 1
  • 前面的话   ES5和ES6致力于为开发者提供JS已有却不可调用的功能。例如在ES5出现以前,JS环境中的对象包含...
    CodeMT阅读 1,523评论 0 2
  • ES:给开发者提供了一个新特性:Proxy,就是代理的意思。也就是我们这一节要介绍的知识点。以前,ATM还没有那么...
    幸宇阅读 467评论 0 0