关于Proxy/reflect(代理/反射)总结

103 阅读2分钟

前言

Vue2实现数据双向绑定监听的核心如下:

// 监听所有的属性: 遍历所有的属性, 对每一个属性使用defineProperty
    const keys = Object.keys(obj)
    for (const key of keys) {
      let value = obj[key]
      Object.defineProperty(obj, key, {
        set: function(newValue) {
          console.log(`监听: 给${key}设置了新的值:`, newValue)
          value = newValue
        },
        get: function() {
          console.log(`监听: 获取${key}的值`)
          return value
        }
      })
    }
  • 缺点:
    ①Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的。我们在定义某些属性的时候,初衷其实是定义普通的属性,但是后面我们强行将它变成了数据属性描述符。
    ②如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的。

在ES6中,新增了一个Proxy类,用于代理。如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象)之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作;

  • Vue3就是基于Proxy来实现的 这是与Vue2最大的区别 为什么快了?因为节约了性能不需要有那么多遍历的耗时操作了!

Proxy的set和get捕获器

image.png

Proxy当中所有捕获器

image.png

仔细看你会发现,返回大多都为boolean,这样就可以过滤掉更多刁钻情况。
举个栗子:

    "use strict"
    const obj = {
      name: "why",
      age: 18
    }

    Object.defineProperty(obj, "name", {
      configurable: false
    })
    // Reflect.defineProperty()
    // 1.用以前的方式进行操作
    // delete obj.name
    // if (obj.name) {
    //   console.log("name没有删除成功")
    // } else {
    //   console.log("name删除成功")
    // }
    // 2.Reflect
    if (Reflect.deleteProperty(obj, "name")) {
      console.log("name删除成功")
    } else {
      console.log("name没有删除成功")
    }

Proxy的construct和apply

image.png

Reflect反射

reflect作用:

  1. 它主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法;
  2. 比如Reflect.getPrototypeOf(target)类似于 Object.getPrototypeOf();
  3. 比如Reflect.defineProperty(target, propertyKey, attributes)类似于Object.defineProperty() ;

疑问?

如果我们有Object可以做这些操作,那么为什么还需要有Reflect这样的新增对象呢?

  1. 这是因为在早期的ECMA规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些API放到了Object上面;
  2. 但是Object作为一个构造函数,这些操作实际上放到它身上并不合适;
  3. 另外还包含一些类似于 in、delete操作符,让JS看起来是会有一些奇怪的;
  4. 所以在ES6中新增了Reflect,让我们这些操作都集中到了Reflect对象上;
  5. 另外在使用Proxy时,可以做到不操作原对象;

reflect常见方法

image.png

Receiver的作用

image.png