跳到主要内容

Reflect

· 阅读需 3 分钟

概念

Reflect 提供了调用对象基本操作(内部方法)的接口

  • ECMA-262 官方文档对于对象的 Internal Methods 有详细描述,比如 [[Get]][[Set]][[OwnPropertyKeys]][[GetPrototypeOf]]

  • MDN 文档对于内部方法的映射,在 Proxy 文档中也有详细说明

也就是说,对象语法层面的操作(对象声明,属性定义与读取等)最终都是通过调用内部方法来完成的

而 Reflect 允许我们直接调用这些内部方法

const obj = {}
obj.a = 1
// 相当于
Reflect.set(obj, 'a', 1)

Why Reflect

当我们使用某个语法或某个 api 来「间接」操作对象时,与直接调用内部方法还是有区别的

也就是说,除了直接调用内部方法以外,这个语法或 api 还会进行一些额外的操作

const obj = {
a: 1,
b: 2,
get c(){
return this.a + this.b
}
}

当我们要用 obj.c 读取属性时,返回了 3,符合我们的预期

但实际上,内部方法 [[Get]] 是需要额外接收 resolver 用来确定 this 指向的

这就说明 obj.c 在读取属性的过程中,一定不只是直接调用内部方法 [[Get]],而是先把 obj 定义为 this,再调用内部方法 [[Get]](obj, 'c', obj),从而获取到 c 属性的值

应用

  • 配合 Proxy 使用

封装代理对象,需要读取某个属性时,this 应该指向代理对象而不是原始对象

const proxy = new Proxy(obj, {
get(target, key) {
console.log('read', key)
// return target[key] // read c
return Reflect.get(target, key, proxy) // read c read a read b
}
})

proxy.c
  • 读取对象的全部属性名

使用 Object.keys(obj)

虽然一开始调用了内部方法 [[OwnPropertyKeys]] 获取到了对象全部的 keys,但紧接着对于不可枚举或 Symbol 类型的属性进行了排除

因此更严谨的获取对象全部自有属性名包括 Symbol 的方法就是直接调用内部方法 Reflect.ownKeys(obj)