Reflect
前言
其实说实在的,在没重学 ES6 之前,我对 Reflect 这个对象完全是空白的,一是在实际工作中用不到,二是面试的时候也没人问起。这也是自己的一个问题,在驱动式学习,而没有去自主学习。
那今天就讲讲 Reflect 对象。
1、概述
Reflect 对象不是构造函数,所以创建时不是用 new 来进行创建。
在 ES6 中增加这个对象的目的:
- 将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上。也就是说,从 Reflect 对象上可以拿到语言内部的方法。
- 修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc)则会返回 false。
- 让 Object 操作都变成函数行为。某些 Object 操作是命令式,比如 name in obj 和 delete obj[name],而 Reflect.has(obj, name)和 Reflect.deleteProperty(obj, name)让它们变成了函数行为。
- Reflect 对象的方法与 Proxy 对象的方法一一对应,只要是 Proxy 对象的方法,就能在 Reflect 对象上找到对应的方法。这就让 Proxy 对象可以方便地调用对应的 Reflect 方法,完成默认行为,作为修改行为的基础。也就是说,不管 Proxy 怎么修改默认行为,你总可以在 Reflect 上获取默认行为。
1 | var loggedObj = new Proxy(obj, { |
上面代码中,每一个 Proxy 对象的拦截操作(get、delete、has),内部都调用对应的 Reflect 方法,保证原生行为能够正常执行。添加的工作,就是将每一个操作输出一行日志。
2、静态 API
Reflect 拥有 13 个静态 API,其大部分与 Object 对象的同名方法的作用都是相同的,而且它与 Proxy 对象的方法是一一对应的。
2.1、Reflect.apply()
通过指定的参数列表发起对目标(target)函数的调用。该方法接受是三个参数,target:目标函数。thisArgument:target 函数调用时绑定的 this 对象。argumentsList:target 函数调用时传入的实参列表,该参数应该是一个类数组的对象。
该方法与 ES5 中 Function.prototype.apply()方法类似,Reflect.apply()可以让代码看起来更加的通俗易懂。
1 | Function.prototype.apply.call(Math.floor, undefined, [1.75]); |
2.2、Reflect.construct()
该方法的行为有点像 new 操作符 构造函数 , 相当于运行 new target(…args)。该方法接受三个参数,target:被运行的目标构造函数。argumentsList:类数组,目标构造函数调用时的参数。newTarget(可选):作为新创建对象的原型对象的 constructor 属性, 参考 new.target 操作符,默认值为 target。
1 | class Person { |
2.3、Reflect.defineProperty()
基本等同于 Object.defineProperty() 方法,唯一不同是返回 Boolean 值。该方法接受三个参数,target:目标对象。propertyKey:要定义或修改的属性的名称。attributes:要定义或修改的属性的描述。
1 | let obj = {}; |
2.4、Reflect.deleteProperty()
允许用于删除属性。它很像 delete operator ,但它是一个函数。该方法接受两个参数,target:删除属性的目标对象。propertyKey:需要删除的属性的名称。
1 | let obj = { |
2.5、Reflect.get()
该方法与从 对象 (target[propertyKey]) 中读取属性类似,但它是通过一个函数执行来操作的。该方法接受三个参数,target:需要取值的目标对象。propertyKey:需要获取的值的键值。receiver:如果 target 对象中指定了 getter,receiver 则为 getter 调用时的 this 值。值得注意的是如果 target 不是对象的话,则会报错。
1 | let obj = { |
2.6、Reflect.getOwnPropertyDescriptor()
该方法与 Object.getOwnPropertyDescriptor() 方法相似。如果在对象中存在,则返回给定的属性的属性描述符。否则返回 undefined。该方法接受两个参数,target:需要寻找属性的目标对象。propertyKey:获取自己的属性描述符的属性的名称。值得注意的是如果 target 不是对象的话,会报错。
1 | var myObject = {}; |
2.7、Reflect.getPrototypeOf()
该方法与 Object.getPrototypeOf() 方法几乎是一样的。都是返回指定对象的原型(即内部的 [[Prototype]] 属性的值)。该方法只能接受一个参数,target:获取原型的目标对象。注意得是如果 target 不是对象的话,会报错。
1 | class MyObj {} |
2.8、Reflect.has()
作用与 in 操作符 相同。该方法接受两个参数,target:目标对象。propertyKey:属性名,需要检查目标对象是否存在此属性。注意,如果目标对象并非 Object 类型,则会报错。
1 | let obj = { |
2.9、Reflect.isExtensible()
判断一个对象是否可扩展 (即是否能够添加新的属性)。与它 Object.isExtensible() 方法相似,但有一些不同,如果该方法的第一个参数不是一个对象(原始值),那么将会报错。对于 Object.isExtensible(),非对象的第一个参数会被强制转换为一个对象。该方法只接受一个参数,target:检查是否可扩展的目标对象。
1 | let obj = {}; |
2.10、Reflect.ownKeys()
返回一个由目标对象自身的属性键组成的数组。该方法接受一个参数,target:获取自身属性键的目标对象。返回一个由目标对象的自身属性键组成的 Array。返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
1 | let myObject = { |
2.11、Reflect.preventExtensions()
该方法阻止新属性添加到对象 (例如:防止将来对对象的扩展被添加到对象中)。该方法与 Object.preventExtensions()相似,但有一些不同点。该方法接受一个参数,target:阻止扩展的目标对象。
1 | let obj = {}; |
2.12、Reflect.set()
该方法设置 target 对象的 name 属性等于 value。该方法接受四个参数,target:设置属性的目标对象。propertyKey:设置的属性的名称。value:设置的值。receiver:如果遇到 setter,receiver 则为 setter 调用时的 this 值。
1 | let person = { |
2.13、Reflect.setPrototypeOf()
该方法与 Object.setPrototypeOf() 方法是一样的。它可设置对象的原型(即内部的 [[Prototype]] 属性)为另一个对象或 null,如果操作成功返回 true,否则返回 false。该方法接受两个参数,target:设置原型的目标对象。prototype:对象的新原型(一个对象或 null)。如果 target 不是对象的话将会报错。
1 | const myObj = {}; |