0
点赞
收藏
分享

微信扫一扫

ES6 中的 ​​Proxy​​​详细使用方法

ES6 中的 Proxy 是一个强大的元编程工具,允许你创建一个对象的代理(Proxy),通过这个代理可以拦截并自定义对象的基本操作(如属性读取、赋值、函数调用等)。下面是 Proxy 的详细使用方法:

1. 基本语法

const proxy = new Proxy(target, handler);

  • target:要代理的目标对象(可以是任何类型的对象,包括数组、函数等)。
  • handler:一个对象,包含拦截操作的“陷阱”(trap)方法(如 get, set, apply 等)。

2. 常见拦截操作(陷阱方法)

以下是常用的 handler 方法:

(1) get(target, prop, receiver)

拦截属性读取操作。

const target = { name: "Alice" };
const handler = {
  get(target, prop) {
    return prop in target ? target[prop] : "Default Value";
  }
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // "Alice"
console.log(proxy.age);  // "Default Value"

(2) set(target, prop, value, receiver)

拦截属性赋值操作。

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({}, handler);
proxy.age = 30; // 正常
proxy.age = "30"; // 抛出错误

(3) apply(target, thisArg, argumentsList)

拦截函数调用操作(当代理目标是函数时)。

const target = function (a, b) { return a + b; };
const handler = {
  apply(target, thisArg, args) {
    console.log(`Calling function with args: ${args}`);
    return target(...args) * 2;
  }
};
const proxy = new Proxy(target, handler);
console.log(proxy(2, 3)); // 输出日志,返回 10

(4) has(target, prop)

拦截 in 操作符。

const handler = {
  has(target, prop) {
    return prop.startsWith("_") ? false : prop in target;
  }
};
const proxy = new Proxy({ name: "Bob", _secret: "123" }, handler);
console.log("name" in proxy); // true
console.log("_secret" in proxy); // false

(5) construct(target, argumentsList, newTarget)

拦截 new 操作符。

class Person {
  constructor(name) { this.name = name; }
}
const handler = {
  construct(target, args) {
    console.log("Creating instance...");
    return new target(...args);
  }
};
const ProxyPerson = new Proxy(Person, handler);
const p = new ProxyPerson("Charlie"); // 输出日志

3. 常见应用场景

(1) 数据验证

通过 set 陷阱验证属性值:

const validator = {
  set(target, prop, value) {
    if (prop === "email" && !value.includes("@")) {
      throw new Error("Invalid email!");
    }
    target[prop] = value;
    return true;
  }
};
const user = new Proxy({}, validator);
user.email = "test@example.com"; // 正常
user.email = "invalid"; // 抛出错误

(2) 观察者模式

监听对象属性的变化:

const observer = {
  set(target, prop, value) {
    console.log(`属性 ${prop} 从 ${target[prop]} 变为 ${value}`);
    target[prop] = value;
    return true;
  }
};
const data = new Proxy({ count: 0 }, observer);
data.count = 1; // 输出日志

(3) 函数钩子

拦截函数调用并添加日志:

const logger = {
  apply(target, thisArg, args) {
    console.log(`函数被调用,参数:${args}`);
    return target.apply(thisArg, args);
  }
};
const sum = (a, b) => a + b;
const proxySum = new Proxy(sum, logger);
proxySum(2, 3); // 输出日志,返回 5

4. 其他特性

(1) Reflect 对象

Reflect 提供了一组与 Proxy 陷阱方法一一对应的方法,通常与 Proxy 配合使用:

const handler = {
  get(target, prop) {
    return Reflect.get(target, prop);
  }
};

(2) 可撤销的 Proxy

通过 Proxy.revocable() 创建可撤销的代理:

const { proxy, revoke } = Proxy.revocable({}, {});
revoke(); // 撤销代理
console.log(proxy.name); // 抛出 TypeError

5. 注意事项

  1. 浏览器兼容性:Proxy 在主流现代浏览器中支持良好,但不支持 IE。
  2. 性能:频繁使用 Proxy 可能影响性能,需谨慎在高性能场景使用。
  3. 透明性:代理后的对象行为可能与原对象不同(如 typeofinstanceof 等操作)。

通过 Proxy,你可以实现高度动态的对象行为控制,非常适合实现高级模式(如响应式系统、AOP编程等)。

举报

相关推荐

0 条评论