Proxy 、Relect、响应式

先来看一下响应式意味着什么?m有一个初始化的值,有一段代码使用了这个值;那么在m有一个新的值时,这段代码可以自动重新执行let m = 0 // 一段代码 console . log(m) console . log(m * 2) console . log(m ** 2) m = 200上面的这样一种可以自动响应数据变量的代码机制,我们就称之为是响应式的对象的响应式。
摘要由CSDN通过智能技术生成

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
    */
    
  • 属性描述符监听对象的缺点:

    • 首先,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
    */
    

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操作
*/

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, argArray)
  },
  construct: function (target, argArray, newTarget) {
   
    console.log(`对 foo 函数进行了 new 调用`)
    return new target(...argArray)
  }
})

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值