初识Reflect

169 阅读3分钟

这是我参与8月更文挑战的第24天,活动详情查看:           8月更文挑战 ​

序言

我们了解了proxy,但是ES6为了操作对象提供的API还有一个Reflect,我们今天就来看一下Reflect有什么不一样。

Reflect概述

Reflect的出现是为了让修改 object 的方法更加合理

  1. 将Object对象的一些语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
  2. 当我们使用Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc) 则会返回false。
// 以往
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // failure
}
​
// 现在
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // failure
}
  1. 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
// 以往
'assign' in Object // true// 现在
Reflect.has(Object, 'assign') // true
  1. Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target, name, value, receiver);
    if (success) {
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});

小结:看上列代码,Proxy方法拦截target对象的属性赋值行为。它采用Reflect.set方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。这样可以保证对象操作的灵活性。

Reflect的静态方法一览

Reflect对象一共有 13 个静态方法。

  1. Reflect.apply(target, thisArg, args)
  2. Reflect.construct(target, args)
  3. Reflect.get(target, name, receiver)
  4. Reflect.set(target, name, value, receiver)
  5. Reflect.defineProperty(target, name, desc)
  6. Reflect.deleteProperty(target, name)
  7. Reflect.has(target, name)
  8. Reflect.ownKeys(target)
  9. Reflect.isExtensible(target)
  10. Reflect.preventExtensions(target)
  11. Reflect.getOwnPropertyDescriptor(target, name)
  12. Reflect.getPrototypeOf(target)
  13. Reflect.setPrototypeOf(target, prototype)

上面这些方法的作用,大部分与Object对象的同名方法的作用都是相同的,而且它与Proxy对象的方法是一一对应的。

常用的方法做详解

Reflect.get(target, name, receiver)

Reflect.get方法查找并返回target对象的name属性,如果没有该属性,则返回undefined。

var myObject = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  },
}
​
Reflect.get(myObject, 'foo') // 1
Reflect.get(myObject, 'bar') // 2
Reflect.get(myObject, 'baz') // 3

如果name属性部署了读取函数(getter),则读取函数的this绑定receiver。

var myObject = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  },
};
​
var myReceiverObject = {
  foo: 4,
  bar: 4,
};
​
Reflect.get(myObject, 'baz', myReceiverObject) // 8

Reflect.set(target, name, value, receiver)

Reflect.set方法设置target对象的name属性等于value。

var myObject = {
  foo: 1,
  set bar(value) {
    return this.foo = value;
  },
}
​
myObject.foo // 1
​
Reflect.set(myObject, 'foo', 2);
myObject.foo // 2
​
Reflect.set(myObject, 'bar', 3)
myObject.foo // 3

如果name属性设置了赋值函数,则赋值函数的this绑定receiver。

var myObject = {
  foo: 4,
  set bar(value) {
    return this.foo = value;
  },
};
​
var myReceiverObject = {
  foo: 0,
};
​
Reflect.set(myObject, 'bar', 1, myReceiverObject);
myObject.foo // 4
myReceiverObject.foo // 1