数据代理

19 阅读4分钟

数据代理

  • what?

    - 通过一个对象代理对另一个对象中的属性的操作(读/写)

    - 数据代理是官方给的说法(名字) , 但是在社区里大家还是都叫数据劫持。因为大家都习惯了这个叫法,而且这个行为也是一个劫持行为。是 ES6 提供的语法 , 是一个内置构造函数。

  • 方法:利用 ES6 新推的一个内置构造函数

  • 语法: const 变量名 = new Proxy(要代理的原始对象,{ 配置项 })

  • 返回值: 一个实例对象 , 就是代理结果数据

  • vue3 中新增的方式,之前的数据劫持方式为 vue2 中内容

案例1

   基础  var o={};
        new Proxy(目标对象,触发手柄对象) 返回一个代理对象
        当修改代理对象时,就会触发修改目标对象
        var p=new Proxy(o,{});
        p.a=10;
        console.log(o)
        Reflect  这个类是对象的反射类,静态方法内容
        
  升级   var o={a:1,b:2};

        var p=new Proxy(o,{

            // target 就是目标对象o

            // key 设置的属性名

            // value 设置的属性值

            // 任何一个事件手柄方法都需要返回一个值

            set(target,key,value){



            //写法1  if(Object.hasOwn(target,key)){

            //         target[key]=value;

            //         return true;

            //    }

            //    return false;

           /*

             Reflect.set(target,key,value):

                   给目标对象target设置key属性的值为value

                   设置成功时 ,不光值改变,还会返回true

            Object.hasOwn(对象,属性名)  判断这个属性名是不是对象的对象属性

                   如果不是对象里面的属性就是false
         */
             写法2   if(!Object.hasOwn(target,key)) return false;

                return Reflect.set(target,key,value)

            }

        })

案例2

    var obj={

            name:"xietian",

            age:30,

            sex:"男",

            tel:"18617890987",

            email:"10398975@qq.com"

        }




        // 设置一个代理对象,只能修改年龄,邮箱,电话,其他属性不能修改也不能添加新的属性




        var p=new Proxy(obj,{

            set(target,key,value){

                if(/age|tel|email/.test(key)){

                    return Reflect.set(target,key,value);

                }

                return false;

            },

            // get 目标  属性名  获取属性

            get(target,key){

              //1. return Reflect.get(target,key); 作用就是下面的2

              //2. return target[key]

              // 只要打印的不是这三个属性就输出空元素

                if(/name|age|sex/.test(key)){

                    return Reflect.get(target,key);

                }

                如果传入的不是这三个属性返回一个空元素

                return null;

            }

        })




        p.age=40;

        p.name="zhangsan"

        p.tel="18790786543"

        console.log(obj)

        console.log(p.age);

        console.log(p.name);

        console.log(p.sex);

        console.log(p.tel);

案例3

    var div=document.querySelector("div");

        var age=new Proxy(div,{

             // p就是代理对象

            set(target,key,value,p){

                if(key==="value"){

                    if(!p.prev) p.prev=target.textContent.split("{")[0]

                    if(!p.next) p.next=target.textContent.split("}").pop();

                   // 重新修改属性值渲染页面

                    return Reflect.set(target,"textContent",p.prev+value+p.next);

                }else if(/prev|next/.test(key)){

                    return Reflect.set(target,key,value);

                }

            },

            get(target,key){

                if(key==="value"){

                    // console.log(target.prev,target.next,target.textContent)

                    // return Reflect.get()

                  var txt=target.textContent.replace(target.prev,"");// 30岁了

                    txt=txt.replace(target.next,"");//30

                    return Number(txt);

                }

                return Reflect.get(target,key);

            }

        })




        age.value=0;

        console.log(age.value)



        setInterval(function(){

            age.value++;

        },1000);

代理的一些属性

set和defineProperty同时使用时的注意点

        var obj={a:1,b:2};




        // set和defineProperty同时使用时,如果仅仅设置值,则触发set,不触发defineProperty

        var p=new Proxy(obj,{

            defineProperty(target,key,desc){

                // Object.defineProperty(target,key,desc)

                desc.enumerable=false;

                return Reflect.defineProperty(target,key,desc);

            }

        })

        p.a=10;

        Object.defineProperty(p,"c",{

            enumerable:false,

            configurable:true,

            writable:true,

            value:3

        })




        p.a=10;

        p.c=20;

        console.log(obj)
        
        

删除

        var obj={a:1,b:2,c:3};


        var p=new Proxy(obj,{

            deleteProperty(target,key){

                // delete target[key]

                // key 属性是a时 ,无法删除

                if(key==="a") return false;

                return Reflect.deleteProperty(target,key);

            }

        })


        delete p.a;

        delete p.b;

        console.log(obj)
        
        
        

返回对象属性的描述对象

        var obj={a:1,b:2,c:3};


        var p=new Proxy(obj,{

            getOwnPropertyDescriptor(target,key){

                // console.log(key)

                if(key==="a") return undefined;//只能返回undefined

                // return Object.getOwnPropertyDescriptor(target,key)

                return Reflect.getOwnPropertyDescriptor(target,key);

            }

        })


    //    var desc=Object.getOwnPropertyDescriptor(p,"b");

        var descs=Object.getOwnPropertyDescriptors(p);

       console.log(descs)
       
       

当获取原型链或者设置原型链

        var o={a:1,b:2};

        var o1=Object.create(o);

        o1.c=3;

        o1.d=4;


      当获取原型链或者设置原型链

        var p=new Proxy(o1,{

            getPrototypeOf(target){

                console.log("aaa")

                // return null; 无法获取原型链

                return Reflect.getPrototypeOf(target);

            },

            setPrototypeOf(target,proto){

                return true;//返回true跳过设置原型链,不修改原型链

                // console.log("bbb")



                return Reflect.setPrototypeOf(target,proto);

            }

        })

        // 这两个调用都会激活getPrototypeOf

        // console.log(Object.getPrototypeOf(p))

        // console.log(p.__proto__);




        // 这两个调用都会激活setPrototypeOf

        var o2={abc:10};

        Object.setPrototypeOf(p,o2);

        // p.__proto__=o2;

        console.log(o1)
        
        

判断对象属性和原型链属性

        var obj={a:1,b:2,c:3};

        var o1=Object.create(obj);

        o1.d=4;

        o1.e=5;


        var p=new Proxy(o1,{

            has(target,key){

                // console.log("aa");

                // return Reflect.has(target,key);

                if(Object.hasOwn(target,key)){

                    return Reflect.has(target,key);

                }

                return false;

            }

        })


        使用 in 判断属性是否在对象中存在,可以判断对象属性和原型链属性

        可以使用has种条件判断是否返回是对象属性还是原型链属性

        console.log("d" in p);

        console.log("a" in p)
        

获取到元素的key列表

            var obj={a:1,b:2,c:3};


        var p=new Proxy(obj,{

            ownKeys(target){

                console.log("aa")

                // 获取到元素的key列表后不能添加只能删除后返回

                var list=Reflect.ownKeys(target);

                list.pop();

                return list;

                // return Reflect.ownKeys(target);

            }

        })




        下面这5个方法都会触发这个内容

        console.log(Object.keys(p))

        console.log(Object.values(p))

        console.log(Object.getOwnPropertyNames(p))

        console.log(Object.getOwnPropertySymbols(p))

        console.log(Reflect.ownKeys(p))
        
        

产生一个代理函数

     var obj={

            a:1,

            getSum(b){

                return this.a+b;

            }

        }


        产生一个代理函数

        var fn=new Proxy(obj.getSum,{

            apply(target,thisArg,argArray){

                // console.log(thisArg) //代表this指向

                thisArg=obj;//固定this指向用于 console.log(fn(1))

               return  Reflect.apply(target,thisArg,argArray);

            }

        })



        console.log(fn(1))

        console.log(fn.call(obj,3))

        console.log(fn.apply(obj,[3]))