在 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]],方法,注意它有个属性
Receiver
,obj.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 文档了解更多。