Reflect ?

How to use Reflect ?

Posted by My on June 18, 2022

在 JavaScript 中,Reflect 对象提供了与 Proxy 对象相同的 API,但其目的在于提供对对象操作的「静态方法」。

什么是对象操作?比如说读取对象的某个属性,

1
2
const obj = { name: "Alice" };
const name = obj.name; // 读取属性

上面的读取方式,是一种语法糖,实际上是通过 get 方法来实现的。

get 方法是对象的基本操作,写为[[GET]]。另外给对象赋值是 set 方法,写为[[SET]]。

而 Reflect 则是可以直接调用对象的基本操作,把原来「对象属性的读取」变为「函数的调用」。

比如,要读取对象的 name 属性,可以用 Reflect.get(obj, 'name') 代替 obj.name

这种封装式的语法糖在某个层面来说,确实好,但是在设计之初,也添加了一些多余的东西,这些多余的东西有时候会让人感到困惑。

比如说有这么一个对象,

1
2
3
4
5
6
const obj = {
  a: 1,
  get b() {
    return this.a + 1;
  },
};

在使用 obj.b 的时候,实际上还是调用了 [[GET]],方法,注意它有个属性 Receiverobj.b 就是默认了 Receiver 就是 obj 本身,导致了 this 是指向 obj 的。因此,this.a就等于 1

如果使用 Reflect.get(obj, 'b') 的话,可以手动指定 Receiver,这样就不会再使用默认的 this 了。

1
2
3
4
5
6
7
const obj = {
  a: 1,
  get b() {
    return this.a + 1;
  },
};
console.log(Reflect.get(obj, "b", { a: 9 })); // 10

这时,this 是指向 {a: 9},所以 this.a 等于 9,所以 obj.b 等于 10

所以总结一下,如果需要灵活的运用对象操作和自定义一些逻辑,建议使用 Reflect 对象,而不要直接使用 obj.xxx 的语法糖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const 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

const myReceiverObject = {
  foo: 4,
  bar: 4,
};
Reflect.get(myObject, "baz", myReceiverObject); // 8

Reflect 还有很多的「静态方法」,比如 Reflect.apply()Reflect.has()Reflect.ownKeys() 等等,可以查看ECMA 262 文档MDN 文档了解更多。