引入
系统学习ES6各种特性,了解背后的原理。
本章记录Reflect
笔记
1.1 Reflect概述
Reflect对象也是ES6中为了操作对象而提供的新的API
设计目的有几点:
- 将
Object对象的一些明显属于语言内部的方法,放到Reflect对象上 - 修改某些
Object方法的返回结果,让其变得更合理(将报错修改为返回false、undefined等) - 让
Object操作行为转换为函数行为,如name in obj可以转换为Reflect.has(obj, name) Reflect对象的方法可以与Proxy的方法适配,这样Proxy中拦截的方法内都可以调用Reflect来保证完成默认的行为,然后再部署额外的行为(比如实现操作日志)。
1.2 静态方法
Reflect对象一种有13个静态方法,大部分与Object对象同名方法作用相同,而且与Proxy对象方法一一对应。
其静态方法都带有一个receiver可选参数,表示调用对应属性或方法的主体对象。
通常情况下,receiver参数是无需使用的,但是如果发生了继承,为了明确调用主体,就需要receiver参数了。
以下列代码为例:
let miaoMiao = {
_name: '疫苗',
get name () {
console.log('getter', this);
return this._name;
}
}
let miaoXy = new Proxy(miaoMiao, {
get (target, prop, receiver) {
console.log('Proxy中拦截的get', receiver._name);
// 此处receiver指向的就不是proxy,而是继承于proxy的对象kexingMiao
return Reflect.get(target, prop, receiver);
// 也可以简写为 Reflect.get(...arguments)
// 此处指定了receiver,即指定了完成默认行为(从miaoMiao上获取name)的this指向
}
});
let kexingMiao = {
__proto__: miaoXy,
_name: '科兴疫苗'
};
console.log(kexingMiao.name);
\\ Proxy中拦截的get 科兴疫苗 在get拦截中receiver指向的是触发get拦截的对象kexingMiao
\\ getter
\\ 科兴疫苗 最后访问到的符合预期的name
代码执行流程解析如下:
- 创建miaoMiao对象,创建该对象的代理miaoXy,以代理对象为原型,新建对象kexingMiao
- 访问kexingMiao的name属性,因为kexingMiao无该属性所以通过原型链在原型上查找
- 在其原型miaoXy上查找时触发Proxy的get拦截,此时get中的receiver指向kexingMiao(get的发起者或者说get返回值的接收者),而target仍然指向该代理的目标miaoMiao。不能想当然地使用
target[prop]来访问name属性(this会指向target自己),而要使用Reflect的receiver改变this指向 - 在get拦截中使用Reflect.get(target, prop, receiver),因此在target查找name属性
- target中有name属性的getter因此访问getter,由于使用了receiver,this指向改变,所以getter返回的
this._name就是我们期望得到的kexingMiao._name
1.2.1 get
Reflect.get(target, name, receiver)
查找并返回target对象的name属性,没有则返回undefined
若target对象的name属性部署了getter那么其this指向由receiver指定
1.2.2 set
Reflect.set(target,name,value,receiver)
注意,若在Proxy的set拦截中使用该方法,还会再次触发defineProperty拦截
1.2.3 has
Reflect.has(target,name)
对应name in obj中的in运算符(显得更高级)
1.2.4 deleteProperty
Reflect.deleteProperty(target,name)
对应delete obj[name],该方法会返回布尔值(不报错),删除失败为false
1.2.5 construct
Reflect.construct(target,args)
等同于new target(...args),提供了一种不使用new来调用构造函数的方法
注意args参数为数组
1.2.6 setPrototypeOf
Reflect.setPrototypeOf(target, prototype)
用于设置对象的_prop_属性,返回第一个参数对象,对应于Object.setPrototypeOf(obj, newProto)
若target不是对象,Reflect的方法会报错而Object的方法会返回第一个参数本身
若第一个参数是null或undefined则都会报错
1.2.7 apply
Reflect.apply(target,thisArg,args)
等同于Function.prototype.apply.call(func, thisArg, args)
一般来说要绑定一个函数的this对象,可以写成fn.apply(thisArg, args)的形式,但是函数若定义了自己的apply方法才要如此复杂
1.2.8 ownKeys
Reflect.ownKeys(target)
该方法用于返回对象的所有属性,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和,比较方便