10.1 使用 Proxy 拦截对象操作

10.1 使用 Proxy 拦截对象操作

Proxy 是 ES6 引入的一种元编程特性,允许你创建一个代理对象,用于拦截和自定义对目标对象的操作。通过 Proxy,你可以实现数据绑定、验证、日志记录等功能。本节将详细介绍 Proxy 的用法及其应用场景。


10.1.1 Proxy 的基本概念

Proxy 用于创建一个代理对象,拦截对目标对象的操作。它接受两个参数:

  • 目标对象(Target):被代理的对象。
  • 处理器对象(Handler):定义拦截操作的陷阱(Trap)。

1. 创建 Proxy

const target = {
  name: "Alice",
  age: 25,
};

const handler = {
  get(target, prop) {
    console.log(`Getting property: ${prop}`);
    return target[prop];
  },
  set(target, prop, value) {
    console.log(`Setting property: ${prop} to ${value}`);
    target[prop] = value;
    return true; // 表示设置成功
  },
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // 输出 "Getting property: name" 和 "Alice"
proxy.age = 26; // 输出 "Setting property: age to 26"

10.1.2 常见的陷阱(Trap)

处理器对象可以定义多种陷阱,用于拦截不同的操作。

1. get
拦截属性的读取操作。

const handler = {
  get(target, prop) {
    console.log(`Getting property: ${prop}`);
    return target[prop];
  },
};

2. set
拦截属性的设置操作。

const handler = {
  set(target, prop, value) {
    console.log(`Setting property: ${prop} to ${value}`);
    target[prop] = value;
    return true; // 表示设置成功
  },
};

3. has
拦截 in 操作符。

const handler = {
  has(target, prop) {
    console.log(`Checking property: ${prop}`);
    return prop in target;
  },
};

console.log("name" in proxy); // 输出 "Checking property: name" 和 true

4. deleteProperty
拦截 delete 操作符。

const handler = {
  deleteProperty(target, prop) {
    console.log(`Deleting property: ${prop}`);
    delete target[prop];
    return true; // 表示删除成功
  },
};

delete proxy.age; // 输出 "Deleting property: age"

10.1.3 Proxy 的应用场景

1. 数据绑定
通过 Proxy 实现数据绑定,自动更新视图。

const data = { name: "Alice" };

const handler = {
  set(target, prop, value) {
    target[prop] = value;
    console.log(`View updated: ${prop} = ${value}`);
    return true;
  },
};

const proxy = new Proxy(data, handler);

proxy.name = "Bob"; // 输出 "View updated: name = Bob"

2. 数据验证
通过 Proxy 实现数据验证,确保数据的合法性。

const user = { age: 25 };

const handler = {
  set(target, prop, value) {
    if (prop === "age" && typeof value !== "number") {
      throw new TypeError("Age must be a number");
    }
    target[prop] = value;
    return true;
  },
};

const proxy = new Proxy(user, handler);

proxy.age = 26; // 正常设置
proxy.age = "26"; // 抛出错误:Age must be a number

3. 日志记录
通过 Proxy 记录对象的操作日志。

const target = { name: "Alice" };

const handler = {
  get(target, prop) {
    console.log(`Getting property: ${prop}`);
    return target[prop];
  },
  set(target, prop, value) {
    console.log(`Setting property: ${prop} to ${value}`);
    target[prop] = value;
    return true;
  },
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // 输出 "Getting property: name" 和 "Alice"
proxy.name = "Bob"; // 输出 "Setting property: name to Bob"

10.1.4 示例代码

示例 1:数据绑定

const data = { name: "Alice" };

const handler = {
  set(target, prop, value) {
    target[prop] = value;
    console.log(`View updated: ${prop} = ${value}`);
    return true;
  },
};

const proxy = new Proxy(data, handler);

proxy.name = "Bob"; // 输出 "View updated: name = Bob"

示例 2:数据验证

const user = { age: 25 };

const handler = {
  set(target, prop, value) {
    if (prop === "age" && typeof value !== "number") {
      throw new TypeError("Age must be a number");
    }
    target[prop] = value;
    return true;
  },
};

const proxy = new Proxy(user, handler);

proxy.age = 26; // 正常设置
proxy.age = "26"; // 抛出错误:Age must be a number

示例 3:日志记录

const target = { name: "Alice" };

const handler = {
  get(target, prop) {
    console.log(`Getting property: ${prop}`);
    return target[prop];
  },
  set(target, prop, value) {
    console.log(`Setting property: ${prop} to ${value}`);
    target[prop] = value;
    return true;
  },
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // 输出 "Getting property: name" 和 "Alice"
proxy.name = "Bob"; // 输出 "Setting property: name to Bob"

10.1.5 总结

  • Proxy:用于创建代理对象,拦截对目标对象的操作。
  • 陷阱(Trap):如 getsethasdeleteProperty 等,用于拦截不同的操作。
  • 应用场景:数据绑定、数据验证、日志记录等。

通过掌握 Proxy,你可以实现更灵活、更强大的对象操作拦截功能。在接下来的学习中,我们将继续探索 JavaScript 的其他高级特性。


思考题

  1. Proxy 的主要作用是什么?
  2. 如何使用 Proxy 实现数据验证?
  3. 在什么情况下应该使用 Proxy 而不是直接操作对象?
#前端开发 分享于 2025-03-21

【 内容由 AI 共享,不代表本站观点,请谨慎参考 】