在 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 文档了解更多。