理解Proxy与Reflect

这章建议直接看原文,引入Reflect主要解决的是当代理getter时的this指向问题(可能也不止有这个问题)

如下代码:

const obj = {
  foo: 1,
  get bar() {
    return this.foo
  }
}

当使用Proxy代理obj时,其中的get函数bar实际返回额是foo的值,而当我们在渲染函数中使用时proxy.bar时,该bar访问的是obj.foo

好吧,其实我没搞懂问题究竟出在哪。

const p = new Proxy(obj, {
  get(target, key) {
    track(target, key)
    // 注意,这里原本没有使用 Reflect.get 完成读取
    // return target[key]

    // 使用 Reflect.get 返回读取到的属性值
    return Reflect.get(target, key, receiver)
  },
  // 省略部分代码
})

为什么要使用Reflect?

  1. 改变代理操作中的正确this指向,在Proxy代理的get/set方法中,最后存在一个参数receiver, 其指向的是代理实例本身,而target指向的是原对象。但是我们的操作是基于代理实例而不是原对象,所以为了前后指向一致(虽然似乎修改原对象好像也没问题,甚至直接使用receiver[key]的方式好像也行)。
  2. 框架健壮性。Reflect针对对象操作拥有更好的错误兼容,例如重复的属性定义,如果使用Object.defineProperty进行同一个属性两次定义会报错, 而如果使用Reflect.defineProperty进行定义则只会在第二次定义返回false,而非报错。并且新的语言内部对象方法将只在Reflect上实现。

JavaScript对象及Proxy的工作原理

JavaScript中一切皆对象

  1. 常规对象
  2. 异质对象(Proxy等,具体看原文)

对象如果没有按照特定版本的ESMA规范定义的内部方法([[GET]],[[SET]],[[Delete]]等)的对象即为异质对象。

而我们在实例化Proxy时传入的get/set拦截方法等则是用来自定义代理本身的内部方法和行为的。

如何代理Object

对一个普通对象所有可能的读取操作