美文网首页
ES6 Proxy代理

ES6 Proxy代理

作者: 幸宇 | 来源:发表于2018-01-19 15:23 被阅读36次

    ES:给开发者提供了一个新特性:Proxy,就是代理的意思。也就是我们这一节要介绍的知识点。
    以前,ATM还没有那么流行的时候(暴露年纪),我们去银行存款或者取款的时候,需要在柜台前排队,等柜台工作人员帮我们办理业务,这也是一种代理,我们自己无法修改我们银行账户上的数据,需要代理给柜员,帮我们办理存钱或者取现业务,而Proxy也是这样的一种机制。

    Proxy的实现

    我们先来看看Proxy的实现:

    //定义一个对象person
        var person = {"name":"张三"};
    
        //创建一个代理对象pro,代理person的读写操作
        var pro = new Proxy(person,{
            get:function(target,property){
                return "李四"
            }
        });
    
        pro.name;//李四
    

    先定义一个对象,含有name属性,值为“张三”,创建一个代理对象pro,对象person的操作都交给代理对象pro,这不,看最后一句代码,如果你要读取person对象的name属性,就要用pro.name,而不是person的name。我们看到的结果是:“李四“而不是person对象重点张三,因为代理过程中,get方法实现了拦截的作用,不管你读取什么属性,我都返回”李四“。
    这就是代理Proxy的作用,将一个对象交给了Proxy代理,然后通过编写处理函数,来拦截目标对象的操作。上面的案例,你可以理解为,person对象的name属性值不想被别人知道是“张三“,就设置了一个代理,让别人读取的时候,只获取到”李四“。

    set方法

    而上面提到的“编写处理函数“,get方法就是其中一个,除了get方法以外,还有一个很常用的是:set方法,它用于拦截对对象的写操作。

    我们来结合银行的例子,来用get方法和set方法的实现,这段代码有点长,但是注释很详细,注意看代码注释:

    //定义一个对象,含有RMB和dollar属性值
        var bankAccount = {"RMB":1000,"dollar":0};
        //创建一个Proxy代理实例
        var banker = new Proxy(bankAccount,{
            //编写get处理程序
            get:function(target, property){
                //判断余额是否大于0
                if(target[property] > 0){
                    //有余额,就返回余额值
                    return target[property];
                }else{
                    //没钱了
                    return "余额不足";
                }    
            },
            //编写set处理程序
            set:function(target,property,value){
                //存入的数额必须是一个数字类型
                if(!Number.isInteger(value)){
                    return "请设置正确的数值";
                }
                //修改属性的值
                target[property] = value;
            }
        });
    
        banker.RMB;
        //结果:1000
        banker.dollar;
        //结果:余额不足
    
        //修改dollar属性的值,值是字符串类型
        banker.dollar = "五百";
        banker.dollar;
        //结果:余额不足
    
        //修改dollar属性的值,值是数字类型
        banker.dollar = 500;
        banker.dollar;
        //结果:500
    

    几乎每一句代码都有注释,这段代码对应的故事情节是这样的:老王有的银行账户里面有一些存款,其中人民币1000元,美元0元。

     var bankAccount = {"RMB":1000,"dollar":0};
    

    有一天,他来到银行柜台前,找到一个叫banker的工作人员,取款之前看看账户里面还有多少钱,然后工作人员banker开始帮他操作(也就是代理)。

    banker.RMB;
        //结果:1000
        banker.dollar;
        //结果:余额不足
    
    

    banker告诉他:“您账户里面有人民币1000元,可以取款的,但美元余额不足“。

        接着,老王不打算取款了,打算存500美元。
    

    在填写存款单据的时候,把500不小心写成了“五百“,banker告诫老王:”这样是写不行的,一定要写阿拉伯数字,这样写银行无法帮您存款的“。结果存款失败,账户里面的美元还是0元。

    banker.dollar = "五百";
        banker.dollar;
        //结果:余额不足
    

    没关系,马上改过来,把“五百“改成500。

    banker.dollar = 500;
        banker.dollar;
        //结果:500
    
    

    存款成功,账户里面的美元已有500元。

    故事的整个经过就是这样,有了Proxy代理(银行工作人员bank),帮助老王完成查看银行存款和取款的操作(代理),避免了一些误操作。

    get方法拦截了读取操作,set方法拦截了改写操作。Proxy除了支持以上拦截程序,还支持一系列的拦截函数,我们选择几个常用的讲解!

    ownKeys( )方法

    ownKeys拦截操作,拦截过滤Object.ownKeys()对对象的属性遍历。

    //定义一个对象person,有三个属性
        let person = {"name":"老王","age":40,"height":1.8};
    
        //创建一个代理对象
        let proxy = new Proxy(person,{
            //ownKeys过滤对对象的属性遍历
          ownKeys:function(target){
                return ["name","age"]
            }
        });
    
        Object.keys(person);
        //结果:["name", "age","height"]
        
        Object.keys(proxy);
        //结果:["name", "age"]
    

    我们编写的ownKeys方法程序,不管你有多少属性,只返回两个属性name和age。我们看最后两行代码:Object.keys(person); 这里我们不使用代理,直接用keys( )函数遍历person对象,得到的person对象的原本属性"name"、 "age"和"height"。而Object.keys(proxy) 这句代码遍历的是被代理的proxy对象,所以,得到的只是被过滤后的结果:[“name”,”age”]。

    has( )方法

    has( )拦截操作:拦截key in object的操作,结果会返回一个布尔值。

    var person = {
            "name":"张三",
            "age":20
        };
    
        var proxy = new Proxy(person, {
            has: function(target, prop) {
                if(target[prop] === undefined){
                    return false;
                }else{
                    return true;
                }
            }
        });
    
        "name" in proxy;//结果:true
        "height" in proxy;//结果:false
    
    

    has( )方法用于是判断是否含有指定的键值对,有,就返回true。否则返回false。
    对象含有name属性,所以返回true,没有height属性,返回false。

    apply( )方法

    除了对象类型的变量可以被代理,函数也可以被代理。如果被代理的变量是一个函数,那么还会支持一个拦截程序:apply调用。

    //创建一个函数fn
        let fn = function(){
            alert('我是前端君');
        };
        //创建一个代理实例,代理函数fn
        let proxy = new Proxy(fn,{
            apply:function(){
                alert('我是隔壁老王');
            }
        });
    
        proxy();//结果:我是隔壁老王
    
    

    最后一句代码,proxy本身是一个代理实例对象,因为它代理的是一个函数fn,所以可以直接用函数的形式调用proxy( );当它当作函数调用的时候,就会被apply拦截,执行alert('我是隔壁老王')。

    Proxy.revocable( )取消代理

    如果创建了代理之后又想取消代理的话,我们可以用Proxy.revocable( )函数来实现,它会返回一个对象,对象中含有一个proxy属性,它就是Proxy的代理实例对象;还有一个revoke属性,它是一个方法,用于取消代理。

    //定义一个对象
        let person = {"name":"张三"};
        //定义一个代理处理程序
        let handle = {
            get:function(target,prop){
                return "李四";
            }
        };
    
        //使用Proxy.revocable()进行代理
        let object = Proxy.revocable(person,handle);
    
        object.proxy.name;//结果:李四
    
        //调用返回对象object的revoke方法,取消代理
        object.revoke();
    
        object.proxy.name;//报错,代理被取消
    

    这个案例大家要注意的是Proxy.revocable( )方法返回的结果,它是一个对象,在控制台打印出来后的结果是:Object{ proxy:Object , revoke:function(){....} }。有一个proxy属性,它就是Proxy代理实例,还有一个属性revoke,它是一个方法,专用于取消代理。

    我们使用object.proxy.name来读取name的属性,由于被代理拦截了,只能读取到“李四”,接着我们调用revoke( )方法取消代理,然后再使用object.proxy.name的时候就会报错了,代理已经不存在了。

    以上就是Proxy代理的介绍,关于其他的拦截操作就不一一介绍,包括:
    defineProperty( )
    deleteProperty( )
    enumerate( )
    getOwnPropertyDescriptor( )
    getPrototypeOf( )
    isExtensible( )
    preventExtensions( )
    setPrototypeOf( )

    本节小结

    总结:ES6带了的Proxy代理机制,它提供了一些拦截操作:set、get、apply、has、ownKeys等,我们可以根据需求编写拦截程序,达到我们想要的效果;此外,还可以利用Proxy.revocable( )实现取消代理。
    摘抄自前端君教程-->
    http://mp.weixin.qq.com/s/jUdSRsF6fBik1ZyVSLAk-g

    相关文章

      网友评论

          本文标题:ES6 Proxy代理

          本文链接:https://www.haomeiwen.com/subject/vunooxtx.html