Proxy

什么是Proxy?

Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。(用来修改某些操作的默认行为)
等同于在语言层面修改,所以属于“元编程”,即对编程语言进行编程。
Proxy可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理,它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时可以添加一些需要的额外的操作。
Proxy可以理解为在目标对象前架设一个“拦截”层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和修改。

基本使用

Proxy构造函数。
let p = new Proxy(target,handler);//返回一个对象(一个Proxy实例)
target:表示所要拦截(代理)的目标对象
handler:是一个对象,用来定制拦截(代理)行为(如set()、get()、deleteProperty()等方法)

Proxy实例的部分方法使用

** set()、get()、apply()、has()**

  1. get(target, property):
    读取代理的目标对象时所要做的事情

  2. set(target,property,value,receiver):
    设置代理目标属性是要做的事情
    参数receiver表示原始操作行为所在对象,一般是Proxy实例本身。

  3. apply(tartget,ctx,args):
    用于拦截函数的调用、call和apply操作。target:目标对象;ctx:目标对象的上下文对象;args:目标对象的参数数组

  4. has(target,propKey):
    拦截propKey in proxy 的操作(拦截HasProperty操作,即判断对象是否具有某一个属性时,返回一个布尔值。不判断继承属性。不拦截for...in循环。
    5.deleteProperty(target,property):
    用于拦截delete操作,如果这个方法抛出错误或者返回false,propKey属性就无法被delete操作删除。

  5. construct(target,args):
    用于拦截new命令。返回值必须为对象。

         let obj = {
             name: '张三'
         };
         let p = new Proxy(obj, {
             get(target, property) { //读取代理的目标对象时所要做的事情
                 //console.log(`读取${property}属性`);
                 //console.log(target[property]);
                 if (property in target) {
                     console.log(target[property]);
                 } else {
                     // throw new Error("没有这个属性");
                     console.error("没有这个属性");
                 }
             },
              set(target, property, value) { //设置代理目标属性是要做的事情
                 console.log("修改属性值");
                 if (property === 'age') {
                     if (!Number.isInteger(value)) {
                         // console.error("年龄必须为整数");
                         throw new Error("年龄必须为整数");
                     }
                     if (value > 200) {
                         console.error("年龄超标了,必须小于200岁")
                     } else {
                         target[property] = value;
                     }
                 }
                 //target[property] = value;
             },
             has(target, propKey) { //拦截propKey in proxy 的操作(拦截HasProperty操作,即判断对象是否具有某一个属性时,返回一个布尔值
                 console.log(propKey in target);
             },
             deleteProperty(target, proKey) {
                 console.log(`要删除${proKey}属性`);
                 delete target[proKey];
             }
         })
         const fn1 = function() {
             return 'I am the target';
         }
         let p2 = new Proxy(fn1, {
             apply(target, ctx, args) {
                 //拦截函数的调用、call和apply操作
                 //target:目标对象;ctx:目标对象的上下文对象;args:目标对象的参数数组
                 console.log("拦截调用");
                 console.log(target()); //I am the target
             }
         })
         let fn2 = function(a, b) {
             return a + b;
         }
         let p3 = new Proxy(fn2, {
             apply(taregt, ctx, args) {
                 console.log(ctx); //p3(1,2):undefined ;p3(null,5,6):null ;Reflect.apply(p3, null, [9, 10]):null
                 console.log(args); //[1,2] [5,6] [9,10]
                 console.log(Reflect.apply(...arguments) * 2); //6 22 38
             }
         })
         p.name;
         p.a;
         p.name = "李四";
         p.name;
         console.log(p); //Proxy {name: "李四"}
         for (let i in p) { //has拦截对for...in循环不生效
             console.log(i); //name
         }
         'name' in p; //true
         'a' in p; //false
         p2(); //p2是proxy的实例,作为函数调用时会被apply方法拦截
         p3(1, 2);
         p3.call(null, 5, 6);
         Reflect.apply(p3, null, [9, 10]);
    

应用:拦截空对象创建DOM元素

     //实例 创建dom元素
     const DOM = new Proxy({}, { //拦截一个空对象
         get(target, property) {
             //property: DOM.xxx 里面的 xxx
             //返回一个创建元素的函数
             return function(attr = {}, ...children) { //属性默认为空,rest参数
                 console.log(attr, children);
                 const el = document.createElement(property);
                 for (let i in attr) {
                     el.setAttribute(i, attr[i]);
                 }
                 for (let child of children) {
                     if (typeof child === 'string') {
                         child = document.createTextNode(child);
                     }
                     el.appendChild(child);
                 }
                 return el;
             }
         }
     })
     let el = DOM.div({
             id: 'box',
             class: 'box'
         }, '哈哈哈', '呵呵呵',
         DOM.a({
             href: 'http://www.baidu.com'
         }, "百度")); //拦截div方法
     console.log(el); //
     let el2 = DOM.ul({
         id: 'ul'
     }, DOM.li({}, '1'), DOM.li({}, '2'), DOM.li({}, '3'));
     window.onload = function() {
         document.body.appendChild(el);
         document.body.appendChild(el2);
     }

运行结果截图
参考

posted @ 2020-10-10 21:21  小耳朵兔  阅读(459)  评论(0)    收藏  举报