ES6 proxy即其常见实例解析以及proxy常用例子

1. proxy 概述

proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种"元编程",即对编程语言进行编程。

proxy可以理解为在目标对象前假设一个“拦截”层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由他来“代理”某些操作,可以翻译为“代理器”.

es6提供proxy构造函数,用于生成proxy实例

proxy对象的所有用法都是上面这种形式,不同的只是handler参数的写法,其中new Peoxy()表示生成一个proxy实例,target参数表示要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

举一个例子:如下

 {
            //举个例子
            let proxy = new Proxy({},{
                get:function(target,property){
                    return 35;
                }
            });
            console.log(proxy.name);
            console.log(proxy.age);
            //proxy就收两个参数,第一个参数是所要代理的目标对象,第二个参数是一个配置对象,需要提供一个相应的处理函数。
            //get方法的两个参数分别是目标对象和索要访问的属性。可以看到拦截函数总是返回35,所以访问任何属性都是得到35
        }

        {
            //如果handler没有设置任何拦截,那就等同于直接通向源对象
            let target = {};
            let handler = {};
            let proxy = new Proxy(target,handler);
            proxy.a = 'b';
            console.log(target.a);  //b
        }

2.proxy实例方法

1.proxy实例方法 --> get()
get方法用于拦截某个属性的读取操作。前面已经有一个例子,下面是另一个拦截读取操作的例子。

        let person = {
            name:'kjh'
        }

        let proxy = new Proxy(person,{
            get(target,property){
                if(property in target){
                    return target[property]
                }else{
                    throw new ReferenceError('Property:'+ property + 'dose not exist!');
                }
            }
        })

        console.log(proxy.name);   //kjh
        console.log(proxy.age);    //age dose not exist!

        上面的代码表示,如果访问目标对象不存在的属性,会抛出一个错误,但是如果没有这个拦截函数,访问不存在的属性,指挥返回undefined


        如果一个属性不可配置或者不可写,那么属性就不能被代理,通过proxy对象访问该属性就会报错。
        {
            let target = {
                name:'123'
            }

            Object.defineProperty(target,'name',{
                writable:false,
                configurable:false
            })

            let proxy = new Proxy(target,{
                get(target,property){
                    return 'abc';
                }
            })
           console.log( proxy.name);
           //property 'name' is a read-only and non-configurable data
        }

2.proxy实例方法 --> set()
set方法用于拦截某个属性的赋值操作


        {
            //加入person对象有一个age属性,该属性应该是一个不大于200的证书,那么proxy可以对象保证age的属性值符合要求
            let validator = {
                set(obj, prop, value){
                    if(prop === 'age'){
                        if(!Number.isInteger(value)){
                            throw new TypeError('The age is not an integer')
                        }
                        if(value > 200){
                            throw new RangeError('The age seems invalid');
                        }
                    }

                    //对于age以外的属性,直接保存
                    obj[prop] = value;
                }
            }

            let person = new Proxy({},validator);
            console.log(person.age = 100);
            console.log(person.age = 201);//The age seems invalid
            console.log(person.age = 'age');  //The age is not an integer


            //上述代码中,由于设置了存值函数set,任何不符合要求的age属性赋值都会抛出一个错误,这是数据验证的一种实现方式.
            //利用set方法还可以实现数据绑定,即每当对象发生变化是,会自动更新DOM.
        }


        {
            //防止内部属性被外部读写
            let handler = {
                get(target ,key){
                    invariant(key, 'get');
                    return target[key];
                },
                set(target, key){
                    invariant(key,'set');
                    target[key] = value;
                    return true;
                    
                }
            }

            function invariant(key, action){
                if(key[0] === '_'){
                    throw new Error(`Invalid attempt to ${action} private "${key}" property` );
                }
            }

            let target = {};
            let proxy = new Proxy(target,handler);
            console.log(proxy._prop);  //Invalid attempt to get private "_prop" property
        }
        

3.proxy实例方法 --> apply()
apply 方法拦截函数的调用,call和apply操作


         apply 方法可以接受三个参数,分别是目标对象,目标对象的上下文对象(this),和目标对象的参数数组

         {
             //举个例子
             let target = function(){
                 return 'I am the target';
             }

             let handler = {
                 apply(){
                     return 'I am the proxy'
                 }
             }

             let p = new Proxy(target,handler);
             console.log(p());  //I am the proxy

             //上面的代码中,变量p是proxy的实例,作为函数调用时就会被apply方法拦截,返回其对应的字符串.
         }

4.proxy实例方法 --> has()
has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效.

 
         {
            //  下面使用has方法隐藏了某些属性,使其不被in运算符发现
            let handler = {
                has(target, key){
                    if(key[0] === '_'){
                        return false;
                    }
                    return key in target;
                }
            }

            var target = {
                _prop:'foo',
                name:'123'
            }

            let proxy = new Proxy(target, handler);
            console.log('_prop' in proxy);  
            //false
         }

        has()方法只拦截in运算符,但是不拦截for...in..运算符
        {
            let stu1 = {
                name:'张三',
                score:56
            }

            let stu2 = {
                name:'李四',
                score:100
            }

            let handler = {
                has(target, prop){
                    if(prop === 'score' && target[prop] < 60){
                        console.log(`${target.name}不及格`);
                        return false
                    }
                    return prop in target;
                }
            }


            let oproxy1 = new Proxy(stu1, handler);
            let oproxy2 = new Proxy(stu2, handler);

            // console.log('score' in oproxy1);
            //张三不及格
            //false

            // console.log('score' in oproxy2);
            //true


            for(let a in oproxy1){
                console.log(oproxy1[a]);
            }
            //张三
            //56

            for(let b in oproxy2){
                console.log(oproxy2[b]);
            }
            //李四
            //100

            // 上面的代码中,has拦截只对in循环生效,对for...in玄幻不生效,导致不符合要求的属性没有被排除在for...of循环外面
        }


5.proxy实例方法 --> construct()
construct方法用于拦截new命令,


        可以接受两个参数,target目标对象和args构建函数的参数对象

        {
            let p = new Proxy(function (){},{
                construct(target, args){
                    console.log('called: '+ args.join(', '));
                    return {
                        value:args[0] * 10
                    }
                }
            })

            console.log((new p(1)).value)
            //called: 1
            //10
        }

        注意返回值必须是一个对象,否则会报错

6.proxy实例方法 --> deleteProperty()
deleteProperty()用于拦截delete操作,返回false,这个属性就无法被删除


        {
            let handler = {
                deleteProperty(target, key){
                    invariant(key, 'delete');
                    return true;
                }
            }

            function invariant(key ,action){
                if(key[0] === '_'){
                    throw new Error(`Invalid attempt to ${action} private "${key}" property` );
                }
            }

            let target = {_name:"kjh"};

            let proxy = new Proxy(target,handler);

            console.log(delete proxy._name); 
            //nvalid attempt to delete private "_name" property

            //上面代码,deletePropertyF方法拦截了delete操作符,删除第一个字符为下划线的属性会报错.
        }

proxy 剩余实例方法和常用的例子将在下一篇介绍。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ES6Proxy是一种特性,它允许我们以一种简洁易懂的方式控制外部对对象的访问。它的功能类似于设计模式中的代理模式。通过创建一个代理对象,我们可以拦截对目标对象的访问并自定义相应的行为。利用Proxy,我们可以实现对对象的属性的读取、写入、删除等操作进行拦截和处理。Proxy 可以作为其他对象的原型对象,也可以用于修改对象的默认行为,从而实现一些高级的功能。例如,我们可以通过Proxy来拦截对对象属性的读取,并在拦截过程中返回我们自定义的值。然而,由于浏览器的兼容性问题以及对Proxy特性的理解程度有限,它在实际开发中的应用相对较少。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ES6Proxy 介绍](https://blog.csdn.net/sinat_17775997/article/details/84233822)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [ES6Proxy](https://blog.csdn.net/m0_62785037/article/details/130714248)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [实例解析ES6 Proxy使用场景介绍](https://download.csdn.net/download/weixin_38663151/14806463)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值