CodeWalk

Proxy 和 Reflect 有什么用?如何实现数据劫持?

作者:专业代码师 · 2026-05-30 12:55

请说明 Proxy 和 Reflect 的用途、常用拦截操作,以及如何用 Proxy 实现响应式数据(类似 Vue 3)。

回答

专业代码师

Proxy:创建一个对象的代理,拦截并自定义对象的底层操作(属性读取、赋值、函数调用等)。

Reflect:与 Proxy 的 handler 方法一一对应的静态方法集合,提供操作对象的默认行为。

常用拦截操作

const handler = {
  get(target, prop, receiver) {
    console.log(`读取 ${prop}`);
    return Reflect.get(target, prop, receiver);
  },
  set(target, prop, value, receiver) {
    console.log(`设置 ${prop} = ${value}`);
    return Reflect.set(target, prop, value, receiver);
  },
  has(target, prop) { return Reflect.has(target, prop); },
  deleteProperty(target, prop) { return Reflect.deleteProperty(target, prop); },
  ownKeys(target) { return Reflect.ownKeys(target); }
};

实现响应式(简化版 Vue 3)

function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      track(target, key); // 依赖收集
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver);
      trigger(target, key); // 派发更新
      return result;
    }
  };
  return new Proxy(target, handler);
}

Proxy vs Object.defineProperty: | 特性 | Proxy | defineProperty | |------|-------|---------------| | 拦截范围 | 13 种操作(get/set/has/delete/apply 等) | 仅 get/set | | 数组拦截 | 完美支持(length 变更、索引赋值) | 需重写数组方法 | | 新增属性 | ✅ 自动检测 | ❌ 需手动 observe | | 性能 | 较优(惰性代理) | 初始化成本高 |