• Object.defineProperty和proxy代理模式


    1. Object.defineProperty

    const obj = {};
    Object.defineProperty(obj,prop,descript);
    
    • 1
    • 2
    参数
    • obj 要定义属性的对象
    • prop 要定义的属性
    • descript 属性描述符

    返回值:被传递给函数的对象
    descript接收一个对象作为配置:

    • writable
      属性是否可写 默认值fasle
    • value
      属性的值 默认值false
    • enumerable
      属性是否可枚举,关系到能否被for…in、Object.keys()以及in关键字遍 默认值false
    • configurable 属性是否可以被defineProperty定义
    • set setter函数
    • get getter函数

    使用defineProperty定义的属性descript默认值全为false

    const obj = {};
    obj.name = 'a';
    //等同于
    Object.defineProperty(obj,'name',{
      configurable: true,
      value: 'a',
      writable: true,
      enumerable: true,
    });
    
    conts obj1 = Object.defineProperty({},'name',{value: 'jack'});
    //等同于
    Object.defineProperty({},'name',{
      value: 'jack',
      enumerable: false,
      writable: false,
      configurable: fasle,
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    value和writable不能和setter与getter一起使用

           const obj = Object.defineProperty({},name,{
            writable:true,
            value: 'jack',
            set:function(newVal){
              return newVal;
            },
            get:function(val){
              return val;
            }
           });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    执行上面的代码出现异常: Uncaught TypeError: property descriptors must not specify a value or be writable when a getter or setter has been specified.

    也就是说我们使用writable和value或者set和get去定义属性的读写,不能混合使用

          const obj = Object.defineProperty({},name,{
            writable:true,
           });
    
            
           const obj1 = Object.defineProperty({},name,{
            set:function(newVal){
              return newVal;
            },
            get:function(val){
              return val;
            }
           });
           
           obj.name = 'ian';
           obj1.name = 'jack';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2. Object.defineProperties

    Object.defineProperties用法与Object.definePropert一致,可以同时定义多个属性

          const obj = Object.defineProperties(obj, {
            name: {
              configurable: true,
              enumerable: true,
              writable: true,
              value: 'ian',
            },
            gender: {
              writable: false,
              value: 'male'
            },
            age: {
              set: function (val) { return val },
              set: function (val) { return val },
            }
          });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3. proxy

    proxy的功能是代理对象,用于拦截对象的基本操作和自定义,与Object.defineProperty类似,区别是proxy代理整个对象,defineProperty只能代理某个属性。

    语法

    const obj = {};
    const proxyObj = new Proxy({obj, handler});
    
    • 1
    • 2

    handler 对象的方法:

    • setProptotypeOf()
      Object.setPropertyOf的捕捉器

    • isExtensible()
      Object.isExtensible的捕捉器

    • preventExtensions()
      Object.preventExtensions方法的捕捉器

    • getOwnPropertyDescritor()
      Object.getOwnPropertyDescriptor方法的捕捉器

    • defineProperty()
      Object.definePropert方法的捕捉器

    • has()
      in操作符的捕捉器

    • deleteProperty()
      delete操作符的捕捉器

    • set
      属性设置操作的捕捉器

    • get
      属性获取操作的捕捉器

    • onwKeys
      Object.getOwnPropertyNames和Object.getOwnSymbos的捕捉器

    • apply
      函数调用操作的捕捉器

    • constructor
      new操作符的捕捉器

      使用get捕捉器

          const obj = { name: 'ian', age: 21 };
          const proxyObj = new Proxy(obj, {
            get: function (obj, prop) {
              return prop in obj ? obj[prop] : 'prop not existent';
            },
          });
          console.log(proxyObj.gender); //prop not existent
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    使用set捕捉器验证属性值

          const obj = { name: 'ian' };
          const proxyObj = new Proxy(obj, {
            set: function (obj, prop, value) {
              if (prop === 'age') {
                if (typeof value !== 'number') {
                  throw new TypeError('The age is not Integer');
                };
                if (value > 200) {
                  throw new RangeError('The age is not invalid');
                };
              }
              obj[prop] = value;
    
              //标识修改成功
              return true;
            }
          });
          proxyObj.gender = 'male'; //male
          proxyObj.age = '二十'; // Uncaught TypeError: The age is not Integer
          proxyObj.age = 201;  //Uncaught RangeError: The age is not invalid
          proxyObj.age = 20; //20
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    捕获new操作符

        function Person(name) {
          this.name = name;
        };
    
        const ProxyPerson = new Proxy(Person, {
          construct: function (target, args) {
            //使用原本的构造函数
            return new Person(...args);
          }
        })
        var jack = new ProxyPerson('jack');
        console.log(jack);//Object { name: "jack" }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    捕获函数调用

        //执行原本的函数
        const proxyFoo = new Proxy(log,{
          apply:function(target,that,args){
            target(args);
          }
        });
        proxyFoo('foo'); //foo
        
        //自定义函数
        const proxyFoo1 = new Proxy(log, {
        apply: function (target, that, args) {
          //将log改成alert执行
          alert(args);
        }
       });
        proxyFoo1('foo'); //foo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    代理模式

    当我们去访问一个数据的时候,不直接去访问数据,而是通过代理(Proxy)作为一个中间者替我们去获取和设置数据,在proxy层可以做一些访问控制等, 例如进行数据的校验数,据合法后再设置给原数据,起到一个保护和校验的功能。常见的代理模式有:

    • 保护代理
      给被调用者提供访问控制,确认调用者的权限
    • 远程代理
    • 虚拟代理
      用来代替巨大的对象,确保在需要的时候才被创建
    • 智能引用代理

    总结

    • proxy是浏览器提供的代理方式,相比较defineProperty来说Proxy更加灵活,能代理对象的多个属性
    • proxy还能捕捉和拦截数组、函数、构造器、以及Object的一些方法和操作符
  • 相关阅读:
    c++对类的的详解(2)
    MySQ 内存使用率高
    腾讯云[HiFlow】| 自动化 -------HiFlow:还在复制粘贴?
    产品运营常用的ChatGPT通用提示词模板
    软考高级系统架构设计师系列之:案例分析典型试题三
    两轮平衡电动车原理简单叙述
    linux安装docker-compose
    【FPGA】Verilog:升降计数器 | 波纹计数器 | 约翰逊计数器 | 实现 4-bit 升降计数器的 UP/DOWN
    Sentinel-限流降级
    值得苦练的100道Python经典练手题,(附详细答案)
  • 原文地址:https://blog.csdn.net/qq_44621394/article/details/126943530