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. 注意事项
- 浏览器兼容性:Proxy 在主流现代浏览器中支持良好,但不支持 IE。
- 性能:频繁使用 Proxy 可能影响性能,需谨慎在高性能场景使用。
- 透明性:代理后的对象行为可能与原对象不同(如
typeof
、instanceof
等操作)。
通过 Proxy
,你可以实现高度动态的对象行为控制,非常适合实现高级模式(如响应式系统、AOP编程等)。