JavaScript中的Reflect
前言
新API,得学学。
Reflect
ES5(ES2015)的新API,看了看MDN的文档,对Reflect的描述
与大多数全局对象不同,
Reflect
不是一个构造函数。你不能将其与一个new
运算符一起使用,或者将Reflect
对象作为一个函数来调用。Reflect
的所有属性和方法都是静态的(就像Math对象)。Reflect
对象提供以下静态函数,它们具有与处理器对象方法相同的名称。这些方法中的一些与Object
上的对应方法相同。
兼容性的话,在MDN上看ie是完全不兼容的,其他浏览器的兼容情况都非常不错。就算不兼容也要学。
Reflect.apply()
类似Function.prototype.apply()
有三个参数
fn
目标函数context
函数执行的上下文arguments
传入fn函数的参数数组(类数组)
返回值为运行绑定了context
之后函数的返回值
1 | function getName() { |
当参数为空的时候,也要传入一个空的数组(或者类数组),不然报错:
CreateListFromArrayLike called on non-object
当上下文无效的时候,会使用全局的对象,NodeJS中为gloabl,浏览器中为window。
Reflect.construct()
相当于用new操作符来新建对象
有三个参数
fn
目标构造函数arguments
传入构造函数的参数数组(类数组)pFn
构造函数(可选)
通过fn
和arguments
初始化的原型为pFn的原型对象(如果有的情况下)的对象。
1 | function Person(){ |
这里的pFn
是一个构造函数,用于指定新创建对象的原型为该构造函数的原型对象。
1 | function Person(){ |
注意此时对象p1的构造函数已经不是Person
了,而是People
,因为js通过挂载在prototype上的constructor属性来判断对象的类型。也就是说,现在p1这个对象用instanceof
判断,Person
为false,而People
为true。
1 | // ... |
在Reflect.construct
这个方法之前,可以用Object.create
和Function.prototype.apply
来类似等效的创建对象。
1 | // 省略Person和People构造函数 |
在MDN上说到一点这两种方式的不同,即在构造函数内部new.target
属性的取值
对于new.target
的取值,可以用下面这段代码验证其指向了构造函数。
1 | function Person(){ |
对于通过Object.create
和Function.prototype.apply
创建的对象,由于没有通过new
创建,内部的new.target
的值会是undefined
。
1 | function Person(){ |
而通过Reflect.construct
来创建的话,new.target
会自动指定到构造函数。(如果指定了pFn
,那指向pFn
,如果没指定,则指向默认,即为fn
)
1 | function Person(){ |
Relfect.defineProperty()
在一个对象上定义属性,类似Object.defineProperty
有三个参数
obj
目标对象propertyKey
定义或者修改的属性名attributes
定义或修改的属性的描述
对于attributes
参数,为一个对象,这个对象可选的键有以下:
configurable
属性是否可以改变和删除,默认为false
enumerable
属性是否可以被枚举,默认为false
value
属性对应的值,默认为undefined
writable
属性是否可写,默认为false
get
属性的getter
函数,默认为undefined
set
属性的setter
函数,默认为undefined
对于这个对象,MDN上有详细的解释,这里就不作详细的展开。
1 | var o = {}; |
和Object.defineProperty
方法唯一不同就是Object.defineProperty
成功定义属性之后会返回传入的对象,失败则会报错。而Reflect.defineProperty
会返回boolean值。
1 | var o = {}; |
Reflect.deleteProperty()
类似delete
操作符
有两个参数
obj
目标对象propertyKey
要删除的属性名
1 | var o = { |
与delete
操作符不同的是,Reflect.deleteProperty
为一个函数,返回boolean,表面是否删除成功。
Reflect.get()
类似obj[propertyKey]
,但是却是通过函数调用来获取属性值。
有三个参数
obj
目标对象propertyKey
需要获取的属性名称context
如果该属性指定了getter,则调用getter时以这个参数为上下文
返回值为该对象的属性名对应的值。
1 | var o = {}; |
Reflect.getOwnPropertyDescriptor()
类似Object.getOwnPropertyDescriptor
。
有两个参数
obj
目标对象propertyKey
需要获取属性描述符的属性名称
1 | var o = {}; |
与Object.getOwnPropertyDescriptor
唯一不同点在与如何如理obj
参数为非对象的情况,如果参数obj
不是对象,Object.getOwnPropertyDescriptor
会强制将其转为对象,而Reflect.getOwnPropertyDescriptor
会报TypeError
错误。
Reflect.getPrototypeOf()
类似与Object.getPrototypeOf
有一个参数
obj
目标对象
返回给定对象obj
的原型对象
和通过属性__proto__
访问的对象时同一个
1 | var o = {}; |
Reflect.has()
检测属性是否存在对象上(包括原型链)
与in
操作符具有相同的效果
有两个参数
obj
目标对象propertyKey
需要检测的属性名
返回boolean值,表示属性是否存在。
1 | var o = { |
Reflect.ownKeys()
返回对象的属性名组成的数组(属性的描述器配置必须是可枚举的)
有一个参数
obj
目标对象
1 | var o = { |
Reflect.preventExtensions()
阻止在一个对象上添加属性,即禁止扩展。
有一个参数
obj
目标对象
返回值为boolean,表示阻止是否成功。
这里需要注意一点,创建出来的对象都是默认可以扩展的,也就是可以添加属性的。
1 | var o = {}; |
Reflect.isExtensible()
判断一个对象是否能够新增属性
有一个参数
obj
目标对象
返回值为boolean,表示该对象是否可以扩展(即是否可以添加属性)
1 | var o = {}; |
Reflect.set()
往对象的属性上设置值
有四个参数
obj
目标对象propertyKey
需要设置值的属性名value
设置的值context
如果该属性指定了setter,则调用setter时以这个参数为上下文(可选)
返回值为boolean,表示设置属性值是否成功
1 | var o = { |
Reflect.setPrototypeOf()
设置对象的原型
有两个参数
obj
目标对象protoObj
原型对象(可为null
)
返回值为boolean,表示设置原型对象是否成功。
1 | var o = {}; |
后记
Reflect
上的方法基本上在Object
上都有相同名字的方法,主要是修改某些Object
上方法的返回值,让其变得合理。new
和delete
等一些命令式操作都可以用函数的方式调用。