JavaScript 中的 Proxy 与 Reflect 分别是什么?两者有什么关系?

2024-08-04 10:55:35 123
在 JavaScript 中,`Proxy` 和 `Reflect` 是两个强大的工具,它们提供了对对象行为的更细粒度的控制和反射能力。下面详细介绍它们及它们之间的关系。

Proxy

Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。通过 Proxy,你可以创建一个对象,在访问或修改该对象时,可以拦截并定义自定义行为。

基本用法

let target = {};
let handler = {
  get: function(target, prop, receiver) {
    console.log(`Getting ${prop}`);
    return prop in target ? target[prop] : 42;
  },
  set: function(target, prop, value, receiver) {
    console.log(`Setting ${prop} to ${value}`);
    target[prop] = value;
    return true;
  }
};

let proxy = new Proxy(target, handler);

console.log(proxy.foo); // Getting foo  ->  42
proxy.foo = 100;        // Setting foo to 100
console.log(proxy.foo); // Getting foo  ->  100

常见的拦截操作

  • get(target, property, receiver): 拦截对象属性的读取。
  • set(target, property, value, receiver): 拦截对象属性的设置。
  • has(target, property): 拦截 property in target 操作。
  • deleteProperty(target, property): 拦截 delete 操作。
  • apply(target, thisArg, argumentsList): 拦截函数调用。
  • construct(target, argumentsList, newTarget): 拦截 new 操作。

Reflect

Reflect 对象提供了一组与 Proxy 对象的方法相同的静态方法。Reflect 主要的作用是对对象的操作提供默认的基本行为,并作为调用 Proxy 拦截方法的原始对象。Reflect 方法的设计使得它们的行为与在严格模式下调用的内置操作一致。

基本用法

let obj = {foo: 1};
console.log(Reflect.get(obj, 'foo')); // 1
Reflect.set(obj, 'foo', 2);
console.log(obj.foo); // 2

常见的 Reflect 方法

  • Reflect.get(target, property, receiver): 与 Proxyget 拦截方法相同。
  • Reflect.set(target, property, value, receiver): 与 Proxyset 拦截方法相同。
  • Reflect.has(target, property): 与 Proxyhas 拦截方法相同。
  • Reflect.deleteProperty(target, property): 与 ProxydeleteProperty 拦截方法相同。
  • Reflect.apply(target, thisArg, argumentsList): 与 Proxyapply 拦截方法相同。
  • Reflect.construct(target, argumentsList, newTarget): 与 Proxyconstruct 拦截方法相同。

Proxy 和 Reflect 的关系

ProxyReflect 密切相关,主要体现在以下几点:

  1. 默认行为Reflect 提供了默认行为,可以在 Proxy 的处理程序中使用 Reflect 方法来调用默认行为。例如,使用 Reflect.get 实现默认的属性访问:

    let handler = {
      get: function(target, prop, receiver) {
        console.log(`Getting ${prop}`);
        return Reflect.get(target, prop, receiver);
      }
    };
    
    let proxy = new Proxy({}, handler);
    console.log(proxy.foo); // Getting foo -> undefined
    
  2. 一致性Reflect 方法的行为与在严格模式下直接调用的内置操作一致,这使得在 Proxy 中调用 Reflect 方法能保证行为一致性。

  3. 方便操作Reflect 提供的静态方法使得对对象的操作更方便且语义更清晰。例如,Reflect.set 与直接使用赋值操作相比,更加直观且避免了一些边界情况。

总结

  • Proxy:用于定义对象基本操作(如属性查找、赋值、枚举等)的自定义行为。通过 Proxy,可以在访问或修改对象时拦截并定义自定义逻辑。
  • Reflect:提供一组与 Proxy 方法相同的静态方法,用于对对象的操作提供默认行为,并保证与严格模式下的内置操作一致。