Skip to content

Reflect

在 ES6 中增加这个对象的目的:

  1. 将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上。也就是说,从 Reflect 对象上可以拿到语言内部的方法。
  2. 修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc)则会返回 false。
  3. 让 Object 操作都变成函数行为。某些 Object 操作是命令式,比如 name in objdelete obj[name],而 Reflect.has(obj, name)Reflect.deleteProperty(obj, name)让它们变成了函数行为。
  4. Reflect 对象的方法与 Proxy 对象的方法一一对应,只要是 Proxy 对象的方法,就能在 Reflect 对象上找到对应的方法。这就让 Proxy 对象可以方便地调用对应的 Reflect 方法,完成默认行为,作为修改行为的基础。也就是说,不管 Proxy 怎么修改默认行为,你总可以在 Reflect 上获取默认行为。
js
var loggedObj = new Proxy(obj, {
  get(target, name) {
    console.log("get", target, name)
    return Reflect.get(target, name)
  },
  deleteProperty(target, name) {
    console.log("delete" + name)
    return Reflect.deleteProperty(target, name)
  },
  has(target, name) {
    console.log("has" + name)
    return Reflect.has(target, name)
  },
})

上面代码中,每一个 Proxy 对象的拦截操作(get、delete、has),内部都调用对应的 Reflect 方法,保证原生行为能够正常执行。添加的工作,就是将每一个操作输出一行日志。

注意: Reflect 不是一个函数对象,因此它是不可构造的。(相当于 Java 的对象提供的全是静态方法,不能被 new 操作)

Reflect.construct

Reflect.construct 其实就是实例化构造函数,通过传参形式的实现, 执行的方式不同, 效果其实一样, construct 的第一个参数为构造函数, 第二个参数由参数组成的数组或者伪数组。

我们先看最基本的两个参数:

js
var date = Reflect.construct(Date, [2020, 5, 15])
console.log(date instanceof Date) // true
console.log(date.getFullYear()) // 2020

其功能就像 new

js
var date = new Date([2020, 5, 15])
console.log(date instanceof Date) // true
console.log(date.getFullYear()) // 2020
  1. 第三个参数 newTarget

新创建对象的原型对象, 参考 new.target 操作符,默认值为 target。

即将 newTarget 原型上的属性复制给 target

js
function OtherClass() {
  console.log("OtherClass")
  console.log(new.target)
  this.age = 100
  this.fAge = "f-100"
}
OtherClass.prototype.fName = "fName"
OtherClass.prototype.name = "f-name"

function OneClass(name, age) {
  console.log("OneClass")
  console.log(new.target)
  this.name = name
  this.age = age
}
OneClass.prototype.name = "c-name"

var result = Reflect.construct(OneClass, ["oneClass", 10], OtherClass)

console.log(result)
console.log(result instanceof OneClass) // false
console.log(result instanceof OtherClass) // true

relect-construct

可见对于第三个参数其作用:

  • 修改了构造函数的指向 (为 OtherClass)

  • 将实例对象的原型链指向 OtherClass 原型链