JavaScript中的Proxy与Reflect API详解
字数 507 2025-11-25 08:26:27

JavaScript中的Proxy与Reflect API详解

描述
Proxy和Reflect是ES6引入的元编程特性,允许你拦截并自定义对象的基本操作。Proxy用于创建对象的代理,可以拦截并重新定义对象的底层操作;Reflect提供了一组与Proxy拦截器对应的方法,用于执行对象的默认行为。

基本概念

  1. Proxy对象包装另一个对象,可以拦截如属性读取、赋值等操作
  2. 每个Proxy都需要一个"处理器"对象,定义拦截行为
  3. Reflect方法对应JavaScript内部方法,如[[Get]]、[[Set]]等

创建Proxy对象

const target = { name: 'John', age: 30 };

const handler = {
  get(target, property, receiver) {
    console.log(`读取属性: ${property}`);
    return target[property];
  },
  set(target, property, value, receiver) {
    console.log(`设置属性: ${property} = ${value}`);
    target[property] = value;
    return true; // 表示设置成功
  }
};

const proxy = new Proxy(target, handler);

Proxy拦截器详解

  1. get拦截器 - 拦截属性读取
const handler = {
  get(target, prop, receiver) {
    if (prop in target) {
      return Reflect.get(target, prop, receiver);
    }
    return `属性 ${prop} 不存在`;
  }
};
  1. set拦截器 - 拦截属性赋值
const handler = {
  set(target, prop, value, receiver) {
    if (prop === 'age' && typeof value !== 'number') {
      throw new TypeError('年龄必须是数字');
    }
    return Reflect.set(target, prop, value, receiver);
  }
};
  1. has拦截器 - 拦截in操作符
const handler = {
  has(target, prop) {
    if (prop.startsWith('_')) {
      return false; // 隐藏私有属性
    }
    return Reflect.has(target, prop);
  }
};

Reflect API的使用
Reflect方法通常与Proxy配合使用,确保正确的this绑定:

const handler = {
  get(target, prop, receiver) {
    // 使用Reflect确保receiver正确传递
    return Reflect.get(target, prop, receiver);
  }
};

实际应用场景

  1. 数据验证
const validator = {
  set(target, prop, value) {
    if (prop === 'email' && !value.includes('@')) {
      throw new Error('无效的邮箱格式');
    }
    if (prop === 'age' && (value < 0 || value > 150)) {
      throw new Error('年龄必须在0-150之间');
    }
    return Reflect.set(target, prop, value);
  }
};

const user = new Proxy({}, validator);
  1. 负索引数组
function createNegativeArray(array) {
  return new Proxy(array, {
    get(target, prop, receiver) {
      const index = Number(prop);
      if (index < 0) {
        prop = String(target.length + index);
      }
      return Reflect.get(target, prop, receiver);
    }
  });
}

const arr = createNegativeArray([1, 2, 3]);
console.log(arr[-1]); // 3(最后一个元素)
  1. 自动观察对象变化
function observable(target) {
  const observers = new Set();
  
  return new Proxy(target, {
    set(target, prop, value, receiver) {
      const oldValue = target[prop];
      const result = Reflect.set(target, prop, value, receiver);
      
      if (result && oldValue !== value) {
        observers.forEach(observer => observer(prop, oldValue, value));
      }
      
      return result;
    }
  });
}

const obj = observable({ count: 0 });
// 可以添加观察者来监听变化

注意事项

  1. this绑定问题
const target = {
  name: 'target',
  getName() {
    return this.name;
  }
};

const proxy = new Proxy(target, {
  get(target, prop, receiver) {
    // 使用Reflect确保方法中的this指向proxy
    const value = Reflect.get(target, prop, receiver);
    return typeof value === 'function' ? value.bind(receiver) : value;
  }
});
  1. 可撤销Proxy
const target = { message: 'hello' };
const { proxy, revoke } = Proxy.revocable(target, {});

console.log(proxy.message); // 'hello'
revoke(); // 撤销代理
// console.log(proxy.message); // 抛出TypeError

性能考虑
Proxy会带来一定的性能开销,在性能敏感的场景中应谨慎使用。但对于需要复杂拦截逻辑的场景,Proxy提供了更优雅的解决方案。

JavaScript中的Proxy与Reflect API详解 描述 Proxy和Reflect是ES6引入的元编程特性,允许你拦截并自定义对象的基本操作。Proxy用于创建对象的代理,可以拦截并重新定义对象的底层操作;Reflect提供了一组与Proxy拦截器对应的方法,用于执行对象的默认行为。 基本概念 Proxy对象包装另一个对象,可以拦截如属性读取、赋值等操作 每个Proxy都需要一个"处理器"对象,定义拦截行为 Reflect方法对应JavaScript内部方法,如[ [ Get]]、[ [ Set] ]等 创建Proxy对象 Proxy拦截器详解 get拦截器 - 拦截属性读取 set拦截器 - 拦截属性赋值 has拦截器 - 拦截in操作符 Reflect API的使用 Reflect方法通常与Proxy配合使用,确保正确的this绑定: 实际应用场景 数据验证 负索引数组 自动观察对象变化 注意事项 this绑定问题 可撤销Proxy 性能考虑 Proxy会带来一定的性能开销,在性能敏感的场景中应谨慎使用。但对于需要复杂拦截逻辑的场景,Proxy提供了更优雅的解决方案。