Reflect 意思是反射,在其它语言中,反射是在程序运行中获取和动态操作自身内容的一项技术。在ES6中提供了Reflect对象,是为了操作对象而提供的新的API。其实对于 JavaScript 来说在出现 Reflect 之前就已经有反射的能力了,我们可以使用 Object.keys() 获取对象属性,可以使用 Object.defineProperty 定义属性,这些实际上都是反射的能力。既然已经可以实现反射功能,那为什么还需要有 Reflect 呢?

1、JS为什么引入Reflect对象?

  • 现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。
  • 修改某些Object方法的返回结果,让其变得更规范化。如Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
  • 让操作对象的从命令式变为函数式编程
  • Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

(1)从Object的命令式编程变为Reflect的函数式编程

1
2
3
4
5
6
7
8
9
10
11
12
// ext 是一个普通对象
// 1. 通过Object获取它的全部属性信息
Object.keys(ext);
// 或者
Object.getOwnPropertyNames(ext);

// 2. 然而这样获取到的只是字符串属性,对象的属性只能是字符串吗?并不是,除了字符串,Symbol 类型也可以作为对象的属性 key,因此上面的代码应该改成这样:
Object.getOwnPropertyNames(ext)
.concat(Object.getOwnPropertySymbols(ext));

// 3. 而使用Reflect获取它的全部属性信息。很明显,效果是完全相同的,但是语义更加明确。
Reflect.ownKeys(ext);

再比如删除属性,在不使用 Reflect 时需要使用 delete 关键字,而使用 Reflect 可以调用上面的 deleteProperty 方法来实现功能,其中的区别在实际开发中可以有更明显的感受。

(2)修改某些Object方法的返回结果,让其更规范化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. 使用 Object.defineProperty 为对象添加属性,如果失败了会直接抛一个异常,因此代码应该是这样的:
try {
Object.defineProperty(obj, prop, attr);
// success
} catch (e) {
// fail
}

// 2. 使用 Reflect 代码就变成下面这样:
if (Reflect.defineProperty(obj, prop, attr)) {
// success
} else {
// fail
}

2、Reflect的相关方法

一共有13个静态方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

3、Reflect搭配Proxy的使用