Reflect
Reflect
基本概念与使用
Reflect
对象与 Proxy 对象一样,也是 ES6
为了操作对象而提供的新 API
。
Reflect
对象的设计目的有这样几个:
-
将
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
上获取默认行为。Proxy 的
handler
(拦截对象支持的拦截操作方法目前有13
种),那么Reflect
也有这13
种静态方法,Reflect.apply, Reflect.get, Reflect.set...
;注意点:这里的
Reflect.apply
其实很有用。比如:
Function.prototype.apply(targetFunc, ctx, argArray)
是无法使用的。但是
Reflect.apply(targetFunc, ctx, argArray)
却可以使用。这里我猜测是因为原生的
apply
底层可能是需要判断this
,也就是判断调用者的类型是不是函数。因此
Function.prototype.apply
用不了,因为此时的调用者是Function.prototype
它的类型是一个对象,而Reflect.apply
缺绕开了这个限制,它的底层应该是有重写。
总结
-
我们用
Reflect
时,可以将其类比为Object
来用,只要是Object
上面的关于语言内部的一些行为的方法,Reflect
上面基本都有对应的方法(虽然有的方法行为和命名可能不同,比如Reflect.ownKeys({}), Object.keys({})
)。关于这两者的区别详情请看:遍历对象属性常用方法;
-
同时,要记得 Proxy 的
handler
对象上可以定义拦截的方法,Reflect
上也都有对应的方法,入参也相同,因此可以用Reflect
来完成 Proxy 中handler
中的一些默认行为;