ES6标准入门 学习笔记 (06)—— Reflect篇

141 阅读3分钟

引入

系统学习ES6各种特性,了解背后的原理。

本章记录Reflect

笔记

1.1 Reflect概述

Reflect对象也是ES6中为了操作对象而提供的新的API

设计目的有几点:

  1. Object对象的一些明显属于语言内部的方法,放到Reflect对象上
  2. 修改某些Object方法的返回结果,让其变得更合理(将报错修改为返回false、undefined等)
  3. Object操作行为转换为函数行为,如name in obj可以转换为Reflect.has(obj, name)
  4. 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

代码执行流程解析如下:

  1. 创建miaoMiao对象,创建该对象的代理miaoXy,以代理对象为原型,新建对象kexingMiao
  2. 访问kexingMiao的name属性,因为kexingMiao无该属性所以通过原型链在原型上查找
  3. 在其原型miaoXy上查找时触发Proxy的get拦截,此时get中的receiver指向kexingMiao(get的发起者或者说get返回值的接收者),而target仍然指向该代理的目标miaoMiao。不能想当然地使用target[prop]来访问name属性(this会指向target自己),而要使用Reflect的receiver改变this指向
  4. 在get拦截中使用Reflect.get(target, prop, receiver),因此在target查找name属性
  5. 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.getOwnPropertyNamesObject.getOwnPropertySymbols之和,比较方便