Reflect为开发者提供了一系列简洁的方法,用于操作对象,特别是结合 Proxy 使用时,Reflect 能够极大地增强元编程的能力,让你轻松实现复杂的功能。
Reflect
Reflect 对象简介
用Object的语法会做一些额外的事情,不直接。
而引入了Reflect就可以通过Reflect来直接调用对象的 内部方法
Reflect 是 ES6 (ECMAScript 2015) 中新增的一个内置对象,它提供了一些方法来处理对象属性的查询和操作。Reflect 对象的方法与 Object 对象的方法相似,但有一些关键的区别:
Reflect的方法不会改变this的指向,而Object方法会。Reflect的方法都是静态的,不能被继承或作为对象的方法调用。Reflect的方法在操作失败时不会抛出异常,而是返回false或undefined。
Reflect 的主要方法
receiver可以用来指定this
Reflect.get(target, propertyKey, receiver)
-
- 获取对象
target上的属性propertyKey的值。 - 如果属性不存在或不可访问,返回
undefined。
- 获取对象
Reflect.set(target, propertyKey, value, receiver)
-
- 设置对象
target上的属性propertyKey的值为value。 - 如果操作失败(如属性是不可写的),返回
false。
- 设置对象
Reflect.has(target, propertyKey)
-
- 检查对象
target是否有属性propertyKey。 - 返回
true或false。
- 检查对象
Reflect.deleteProperty(target, propertyKey)
-
- 删除对象
target上的属性propertyKey。 - 如果删除成功,返回
true;如果属性是不可配置的,则返回false。
- 删除对象
Reflect.ownKeys(target)
-
- 返回对象
target的所有自有属性的键名,包括 Symbol 类型的键名。
- 返回对象
Reflect.getOwnPropertyDescriptor(target, propertyKey)
-
- 返回对象
target上属性propertyKey的描述符。 - 如果属性不存在,返回
undefined。
- 返回对象
Reflect.defineProperty(target, propertyKey, attributes)
-
- 定义或修改对象
target上属性propertyKey的描述符。 - 如果操作失败(如属性是不可配置的),抛出异常。
- 定义或修改对象
Reflect.preventExtensions(target)
-
- 阻止对象
target被扩展。 - 如果对象已经被阻止扩展,返回
true;否则返回false。
- 阻止对象
Reflect.isExtensible(target)
-
- 检查对象
target是否可以被扩展。 - 返回
true或false。
- 检查对象
Reflect.getOwnPropertyDescriptors(target)
-
- 返回对象
target的所有自有属性的描述符。
- 返回对象
Reflect.apply(target, thisArgument, argumentsList)
-
- 调用
target函数,将this绑定到thisArgument上,并传入argumentsList作为参数数组。
- 调用
Reflect.construct(target, argumentsList, newTarget)
-
- 使用
target构造函数创建一个新对象,传入argumentsList作为参数数组。 - 如果提供了
newTarget,则使用newTarget作为构造函数的原型。
- 使用
示例
const obj = { x: 1, y: 2 };
// 使用 Reflect.get 获取属性
const x = Reflect.get(obj, 'x'); // x => 1
// 使用 Reflect.set 设置属性
const success = Reflect.set(obj, 'z', 3); // success => true
console.log(obj.z); // 3
// 使用 Reflect.has 检查属性
const hasY = Reflect.has(obj, 'y'); // hasY => true
// 使用 Reflect.deleteProperty 删除属性
const deleted = Reflect.deleteProperty(obj, 'x'); // deleted => true
console.log(obj.x); // undefined
Proxy和Reflect的配合使用
为什么Proxy一定要配合Reflect使用?恰恰是为了触发代理对象的劫持时保证正确的 this 上下文指向。
针对于 get 陷阱(当然 set 其他之类涉及到 receiver 的陷阱同理):
- Proxy 中接受的 Receiver 形参表示 代理对象本身或者继承与代理对象的对象 。
- Reflect 中传递的 Receiver 实参表示 修改执行原始操作时的 this 指向。
const obj = {
a: 1,
b: 2,
// 定义一个 getter 属性 c,计算 a 和 b 的和
get c() {
return this.a + this.b;
}
};
// 创建一个 Proxy 对象,用于拦截对 obj 的访问
const proxy = new Proxy(obj, {
// 当访问 obj 的属性时触发 get 操作
get(target, key) {
console.log('正在访问:', key);
// return target[key];
// 当直接返回 target[key] 时,此时的this就指向target,只输出正在访问的属性名称和最终的值
// 正在访问: c
// 3
return Reflect.get(obj, key, proxy);
// 如果使用 Reflect.get 方法,此时把this的值绑定到proxy上,则会输出所有访问路径上的属性名
// 正在访问: c
// 正在访问: a
// 正在访问: b
// 3
}
});
// 访问 proxy 对象的属性 c,触发了拦截器中的 get 操作
console.log(proxy.c);