为什么是Reflect.get, 而不是target[key]?
vue3源码中看到下面这样一段代码. 创建代理时, Proxy的get钩子中返回数据使用了Reflect.get(target, key, receiver). 第一反应是这又是啥花里胡哨的玩意? 为什么不直接用target[key]? 仅仅是为了使用新语法么? 不用行不行?
答案当然是不行的.
1 | const shallowUnwrapHandlers = { |
什么是Reflect
Reflect是一个全局对象.其提供了很多方法, 并且任何在Proxy的拦截器中能够找到的方法, 都能够在Reflect中找到同名函数. 下面是所有方法及说明
| 方法 | 说明 |
|---|---|
| Reflect.aply(target, thisArgument, argumentsList) | 对一个函数进行调用操作, 与Function.prototype.apply功能类似 |
| Reflect.construct(target, argumentsList[, newTarget]) | 对构造函数进行new操作, 相当于执行new target(…args) |
| Reflect.defineProperty(target, propertyKey, attributes) | 和Object.defineProperty类似, 如果设置成功就返回true |
| Reflect.deleteProperty(target, propertyKey) | 作为函数的delete操作符, 相当于执行 delete target[key] |
| Reflect.get(target, propertyKey[, receiver]) | 获取对象身上某个属性的值, 类似于target[name] |
| Reflect.getOwnPropertyDescriptor(target, propertyKey) | 类似于Object.getOwnPropertyDescriptor, 如果对象中存在该属性, 则返回对应的属性描述符, 否则返回undefined |
| Reflect.getPrototypeOf(target) | 类似于Object.getPrototypeOf() |
| Reflect.has(target, propertyKey) | 判断一个对象是否存在某个属性, 和 in 运算符的功能完全相同 |
| Reflect.isExtensible(target) | 类似于Object.isExtensible() |
| Reflect.ownKeys(target) | 返回一个包含所有自身属性(不包含继承属性)的数组. (类似于Object.keys(), 但不会受enumerable影响) |
| Reflect.preventExtensions(target) | 类似于Object.preventExtensions(), 返回Boolean |
| Reflect.set(target, propertyKey, value[, receiver]) | 将值分配给属性的函数. 返回Boolean. 更新成功返回true |
| Reflect.setPrototypeOf(target, prototype) | 设置对象原型的函数. 返回Boolean, 更新成功返回true |
target[key]会有什么问题
给需要监听的obj一个访问器属性, 返回this.foo的值. 然后在effect副作用函数中通过代理对象p来访问bar属性. 然后改变p.foo的值.
我们期望的输出当然是随着p.foo改变, 副作用函数再次执行. 但是实际输出与预期并不符.
1 | const obj = { |
输出结果:
1 | 1 |
控制台只输出了一次1. 当p.foo=10执行时, 副作用函数并没有被执行. 为什么?
给访问属性添加输出日志
1 | const obj = { |
输出结果:

此时bar函数的this指向原始对象本身. 所以在副作用函数中访问p.bar 等价于访问obj.foo. 自然也不会建立响应联系了.
那怎么做才能让bar函数中的this指向代理对象呢?
Reflect.get
Reflect.get(target, propertyKey[, receiver])接受三个参数, 其中receiver代表谁在读取属性
修改代码
1 | const obj = { |
// 输出结果
1 | 1 |