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属性是否可以改变和删除,默认为falseenumerable属性是否可以被枚举,默认为falsevalue属性对应的值,默认为undefinedwritable属性是否可写,默认为falseget属性的getter函数,默认为undefinedset属性的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等一些命令式操作都可以用函数的方式调用。