Reflect 对象是 ES6 提供的一个内置的用于操作对象的的全局对象。但和其他的全局对象不同,Reflect 对象没有构造函数,不能使用 new关键字 创建对象。
Reflect 静态方法
Reflect 对象提供以下静态函数,大部分与 Object 对象上同名方法的作用一样,同时将一些命令式的语法函数化。
Reflect.apply
静态方法 Reflect.apply() 通过指定的参数列表发起对目标函数的调用,类似于 Function.prototype.apply.call(target, thisArgument, argumentsList)
Reflect.apply(target, thisArgument, argumentsList)
- target: 目标函数
- thisArgument: 绑定的 this 对象
- argumentsList: target函数调用时传入的实参列表,该参数应该是一个类数组的对象
- throws: 如果
target
不可被调用抛出TypeError
异常
一般来说,若需要绑定函数的 this 对象通常可以 func.apply(obj, args)
但是有时候函数可能自定义了 apply
方法,为了方便,我们可能需要写成 Function.prototype.apply.call(func, obj, args)
,而采用 Reflect.apply,可以简化操作,并且更容易理解:
// 除非确认 func.apply 未被其他人定义或改写,方可使用 |
Reflect.construct
对构造函数进行 new 操作,相当于执行 new target(…args),提供了一种不使用new,来调用构造函数的方法。
Reflect.construct(target, argumentsList[, newTarget])
- target: 目标对象
- argumentsList: 参数列表
- [newTarget[Function]]: 可省略,类似于
new.target
操作符,指向构造方法或函数的引用 - throws: 如果
target
或者newTarget
不是构造函数,抛出TypeError
异常
function Foo(val) { |
使用 newTarget
参数:
function newTarget() {} |
顺便提下,在普通的函数调用中(和作为构造函数来调用相对),new.target
的值是 undefined
,因此可以用来检测是否将构造函数作为普通函数调用:
function Foo() { |
Reflect.defineProperty
精确添加或修改对象上的属性,和 Object.defineProperty
类似。
Reflect.defineProperty(target, propertyKey, attributes)
Object.defineProperty
返回结果为第一个参数对象,而 Reflect.defineProperty
返回结果为布尔型,表示操作是否成功,两者检查操作结果方式如下:
// Object.defineProperty |
Reflect.deleteProperty
删除对象的某个属性,类似于执行 delete target[name],区别在于一个是操作符,一个是函数调用。
Reflect.deleteProperty(target, propertyKey)
// 使用 delete |
Reflect.enumerate
已过时
Reflect.get
获取对象上某个属性的值,类似于 target[propertyKey]。
Reflect.get(target, propertyKey[, receiver])
- target: 目标对象
- propertyKey: 需要获取的值的键值
- [receiver]: 可省略,如果遇到
getter
,则getter
中this
指向的上下文为receiver
。 - return[Any]: 任意类型
Reflect.get({x: 1, y: 2}, x) // 1 |
注意:第三个参数表示使用指定的 receiver
,表示指定的 getter
中存在的 this
指向的上下文:
var foo = { |
Reflect.set
设置对象身上某个属性的值,类似于 target[name] = val。
Reflect.set(target, propertyKey, value[, receiver])
- target: 目标对象
- propertyKey: 需要获取的值的键值
- [receiver]: 可省略,如果遇到
setter
,则setter
中this
指向的上下文为receiver
。 - return[Boolean]: 任意类型
var obj = { |
注意:第三个参数表示使用指定的 receiver
,表示指定的 setter
中存在的 this
指向的上下文:
var foo = { |
如果第一个参数不是对象,Reflect.set
会报错。
Reflect.getOwnPropertyDescriptor
如果属性在对象中存在,则返回给定的属性的属性描述符,否则返回 undefined
。类似于 Object.getOwnPropertyDescriptor()
,唯一不同在于 Object
对非对象参数会进行强制类型转换,Reflect
会抛出 TypeError
异常。
Reflect.getOwnPropertyDescriptor(target, propertyKey)
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x"); |
这两个的区别是 Object.getOwnPropertyDescriptor
会包装非对象参数,将其强制转换为对象, Reflect.getOwnPropertyDescriptor
会抛出 TypeError
异常:
Reflect.getOwnPropertyDescriptor("x", 0); |
Reflect.getPrototypeOf
返回指定对象的原型。类似于 Object.getPrototypeOf
,唯一不同在于 Object
对非对象参数会进行强制类型转换,Reflect
会抛出 TypeError
异常。
Reflect.getPrototypeOf(target)
var proto = {}; |
如果参数为非对象,将抛出 TypeError 异常,而 Object.isExtensible 会将其强制转换为一个对象:
Object.isExtensible(1); // false |
Reflect.setPrototypeOf
给对象设置原型, 即更改对象的 __proto__
属性。类似于 Object.setPrototypeOf()。
Reflect.setPrototypeOf(target, prototype)
注意:如果第一个非对象参数 Object
会对直接返回该参数,Reflect
会抛出 TypeError
异常:
Object.setPrototypeOf(1, {}); //1 |
注意:prototype 只能为 Object
或者 null
,否则也会抛出 TypeError
异常:
Object.setPrototypeOf({}, 1); |
Reflect.has
判断一个对象是否存在某个属性,和 in 操作符
的功能相同
Reflect.has(target, propertyKey)
var obj = { |
Reflect.isExtensible
判断一个对象是否可以扩展。类似于 Object.isExtensible
,唯一不同在于 Object
对非对象参数会进行强制类型转换,Reflect
会抛出 TypeError
异常。
Reflect.isExtensible(target)
var obj = {}; |
Reflect.ownKeys
返回一个包含所有自身属性(不包含继承属性)的数组。Object 对象不存在这个方法,而是提供两个独立的方法:getOwnPropertyNames
和 getOwnPropertySymbols
。Reflect.ownKeys
返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
。
Reflect.ownKeys(target)
var obj = { |
Reflect.preventExtensions
用于让一个对象变为不可扩展,返回布尔值,表示是否操作成功,类似于 Object.preventExtensions, Object
对非对象参数会进行强制类型转换,Reflect
会抛出 TypeError
异常。
Reflect.preventExtensions(target)
var obj = {}; |
这两个函数都只能阻止一个对象不能再添加新的自身属性,仍然可以为该对象的原型添加属性:
var obj = {}; |
注意:使用 Object.defineProperty
或 Reflect.defineProperty
方法为一个不可扩展的对象添加新属性会抛出异常:
var obj = { removable: true }; |
注意:在严格模式下,为不可扩展对象添加新属性会抛出TypeError异常:
var obj = { removable: true }; |
总结
Reflect 上的几乎所有操作都是原本存在的操作, Reflect 对其做了统一的整合,具有以下优点:
将对象上的操作函数化
过去的某些对象上的操作是命令式的,如 name in obj
、 delete obj[name]
, Reflect 将这些操作统一为函数调用
name in obj |
更有用的返回值
Reflect 上有好些方法和 Object 上的一样,但是修改了返回的结果,比如 Object.defineProperty
在无法定义属性时,会抛出错误, Reflect 则返回 false
// Object.defineProperty |
其他相似的方法如 Reflect.deleteProperty
、 Reflect.preventExtensions
、 Relect.set
、 Reflect.setPrototypeOf
也是如此。
控制访问器中 this 的绑定
Reflect.get
和 Reflect.set
通过提供额外的第三个参数 receiver
可以方便的控制访问器 getter
和 setter
中的 this
的指向,比如在访问器中不想使用自己的属性或方法,而是使用包装器的属性或方法:
var obj = { |
提供和 Proxy 一一对应的方法
Proxy 对象支持的所有方法都可以在 Reflect 上找到,Proxy 对象可以方便地调用对应的 Reflect 方法,执行基础的操作。同时,不论 Proxy 做了怎样的修改,都可以通过 Reflect 获取原始行为。
浏览器兼容性
Chrome | Edge | Firefox | IE | Opera | Safari |
---|---|---|---|---|---|
49.0 | Yes | 42.0 | 未实现 | 未实现 | 10 |