• Proxy 、Relect、响应式


    Proxy 、Relect、响应式

    1. 监听对象的操作

    • 需求:有一个对象,我们希望监听这个对象中的属性被设置或获取的过程

      • 可以通过属性描述符中的存储属性描述符来做到
    • 这段代码就利用了 Object.defineProperty 的存储属性描述符来对属性的操作进行监听

      const obj = {
           
        name: 'why',
        age: 18
      }
      
      Object.keys(obj).forEach((key) => {
           
        let value = obj[key]
        Object.defineProperty(obj, key, {
           
          get: function () {
           
            console.log(`监听到obj对象的${
             key}属性被访问了`)
            return value
          },
          set: function (newValue) {
           
            console.log(`监听到obj对象的${
             key}属性被设置值`)
            value = newValue
          }
        })
      })
      
      obj.name = 'kobe'
      obj.age = 30
      console.log(obj.name)
      console.log(obj.age)
      /* 
      监听到obj对象的name属性被设置值
      监听到obj对象的age属性被设置值
      监听到obj对象的name属性被访问了
      kobe
      监听到obj对象的age属性被访问了
      30
      */
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
    • 属性描述符监听对象的缺点:

      • 首先,Object.defineProperty 设计的初衷,不是为了去监听截止一个对象中所有的属性的
        • 我们在定义某些属性的时候,初衷其实是定义普通的属性,但是后面我们强行将它变成了数据属性描述符
      • 其次,如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么 Object.defineProperty 是无能为力的
      • 所以我们要知道,存储数据描述符设计的初衷并不是为了去监听一个完整的对象
      • Ps: 原来的对象是 数据属性描述符,通过 Object.defineProperty 变成了 访问属性描述符

    2. Proxy基本使用

    • 在ES6中,新增了一个Proxy类,这个类从名字就可以看出来,是用于帮助我们创建一个代理的:

      • 也就是说,如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象)
      • 之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作
    • 将上面的案例用 Proxy 来实现一次:

      • 首先,我们需要 new Proxy 对象,并且传入需要侦听的对象以及一个处理对象,可以称之为 handler
    • const p = new Proxy(target, handler)

    • 其次,我们之后的操作都是直接对 Proxy 的操作,而不是原有的对象,因为我们需要在 handler 里面进行侦听

      const obj = {
           
        name: 'why',
        age: 18
      }
      
      const objProxy = new Proxy(obj, {
           
        // 获取值时的捕获器
        get: function (target, key) {
           
          console.log(`监听到obj对象的${
             key}属性被访问了`)
          return target[key]
        },
        // 设置值时的捕获器
        set: function (target, key, newValue) {
           
          console.log(`监听到obj对象的${
             key}属性被设置值`)
          target[key] = newValue
        }
      })
      
      console.log(objProxy.name)
      console.log(objProxy.age)
      
      objProxy.name = 'kobe'
      objProxy.age = 30
      
      console.log(obj.name)
      console.log(obj.age)
      
      /* 
      监听到obj对象的name属性被访问了
      why
      监听到obj对象的age属性被访问了
      18
      监听到obj对象的name属性被设置值
      监听到obj对象的age属性被设置值
      kobe
      30
      */
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43

    2.1 Proxy 的 set 和 get 捕获器

    • 如果我们想要侦听某些具体的操作,那么就可以在 handler 中添加对应的捕捉器(Trap)
    • setget 分别对应的是函数类型
      • set 函数有四个参数:
        • target:目标对象(侦听的对象)
        • property:将被设置的属性 key
        • value:新属性值
        • receiver:调用的代理对象
      • get 函数有三个参数
        • target:目标对象(侦听的对象)
        • property:被获取的属性 key
        • receiver:调用的代理对象

    2.2 Proxy 所有捕获器 (13个)

    • handler.getPrototypeOf()

      • Object.getPrototypeOf 方法的捕捉器
    • handler.setPrototypeOf()

      • Object.setPrototypeOf 方法的捕捉器
    • handler.isExtensible()

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

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

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

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

      • Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器
    • handler.has()

      • in 操作符的捕捉器
    • handler.get()

      • 属性读取操作的捕捉器
    • handler.set()

      • 属性设置操作的捕捉器
    • handler.deleteProperty()

      • delete 操作符的捕捉器
    • handler.apply()

      • 函数调用操作的捕捉器
    • handler.construct()

      • new 操作符的捕捉器
    const obj = {
       
      name: 'why',
      age: 18
    }
    
    const objProxy = new Proxy(obj, {
       
      // 获取值时的捕获器
      get: function (target, key) {
       
        console.log(`监听到obj对象的${
         key}属性被访问了`)
        return target[key]
      },
      // 设置值时的捕获器
      set: function (target, key, newValue) {
       
        console.log(`监听到obj对象的${
         key}属性被设置值`)
        target[key] = newValue
      },
      // 监听 in 的捕获器
      has: function (target, key) {
       
        console.log(`监听到obj对象的${
         key}属性的in操作`)
        return key in target
      },
      // 监听 delete 的捕获器
      deleteProperty: function (target, key) {
       
        console.log(`监听到obj对象的${
         key}属性的delete操作`)
        delete target[key]
      }
    })
    
    // in 操作符
    console.log('name' in objProxy)
    
    // delete 操作
    delete objProxy.name
    
    /* 
    监听到obj对象的name属性的in操作
    true
    监听到obj对象的name属性的delete操作
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    2.3 Proxy 的 construct 和 apply

    • 到捕捉器中还有 constructapply,它们是应用于函数对象的
    function foo() {
       
      console.log('调用了 foo')
    }
    
    const fooProxy = new Proxy(foo, {
       
      apply: function (target, thisArg, argArray) {
       
        console.log(`对 foo 函数进行了 apply 调用`)
        target.apply(thisArg
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    Maven添加SQLserver的依赖及驱动
    海外媒体发稿:彭博社发稿宣传中,5种精准营销方式
    在Windows环境与Linux环境下搭建Zookeeper单机环境与集群环境
    HBase优化
    服务器密码以及用户名怎么修改
    winform 获取指定的form
    【Matplotlib绘制图像大全】(二十七):Matplotlib将数组array保存为图像
    从零开始 Spring Boot 21:Activiti
    K8S知识点(九)
    数字图像处理复习
  • 原文地址:https://blog.csdn.net/wanghuan1020/article/details/126774033