在 JavaScript 中,Proxy 是一种强大的工具,它允许你通过拦截对象的基本操作(如属性访问、赋值、函数调用等)来定义自定义行为。Proxy 是在 ECMAScript 6(ES6)中引入的,主要用于增强对象的功能和行为。
基本语法
const proxy = new Proxy(target, handler);
target
:需要代理的目标对象(可以是普通对象、数组或另一个 Proxy)。handler
:一个对象,包含特定操作的拦截方法(称为“trap”)。
常用 handler
的拦截方法(Trap)
以下是 Proxy 支持的常用 trap 方法,以及它们的用途:
Trap | 用途 |
---|---|
get | 拦截属性读取,例如 proxy.prop 。 |
set | 拦截属性赋值,例如 proxy.prop = value 。 |
has | 拦截属性检查,例如 'prop' in proxy 。 |
deleteProperty | 拦截属性删除,例如 delete proxy.prop 。 |
ownKeys | 拦截对象自身属性的枚举,例如 Object.keys(proxy) 或 for...in 循环。 |
apply | 拦截函数调用,例如 proxy() 。 |
construct | 拦截构造函数调用,例如 new proxy() 。 |
常见用法示例
1. 属性读取拦截
const person = {
name: "Alice",
age: 25
};
const proxy = new Proxy(person, {
get(target, prop) {
if (prop in target) {
return target[prop];
} else {
return `Property "${prop}" does not exist.`;
}
}
});
console.log(proxy.name); // 输出: Alice
console.log(proxy.gender); // 输出: Property "gender" does not exist.
2. 属性赋值拦截(数据验证)
const person = {
name: "Alice",
age: 25
};
const proxy = new Proxy(person, {
set(target, prop, value) {
if (prop === "age" && typeof value !== "number") {
throw new TypeError("Age must be a number.");
}
target[prop] = value;
return true; // 必须返回 true,表示成功
}
});
proxy.age = 30; // 正常赋值
console.log(proxy.age); // 输出: 30
proxy.age = "thirty"; // 抛出错误: Age must be a number
3. 日志记录
const person = {
name: "Alice",
age: 25
};
const proxy = new Proxy(person, {
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;
}
});
console.log(proxy.name); // 输出日志并获取值
proxy.age = 26; // 输出日志并更新值
4. 禁止删除属性
const person = {
name: "Alice",
age: 25
};
const proxy = new Proxy(person, {
deleteProperty(target, prop) {
if (prop === "name") {
throw new Error("Cannot delete 'name'");
}
delete target[prop];
return true;
}
});
delete proxy.age; // 成功
console.log(proxy); // 输出: { name: 'Alice' }
delete proxy.name; // 抛出错误: Cannot delete 'name'
5. 拦截数组操作
const numbers = [1, 2, 3];
const proxy = new Proxy(numbers, {
get(target, prop) {
if (prop === "last") {
return target[target.length - 1];
}
return target[prop];
},
set(target, prop, value) {
if (prop === "length" && value < target.length) {
throw new Error("Cannot shrink the array.");
}
target[prop] = value;
return true;
}
});
console.log(proxy.last); // 输出: 3
proxy.push(4); // 正常操作
console.log(proxy); // 输出: [1, 2, 3, 4]
proxy.length = 2; // 抛出错误: Cannot shrink the array.
6. 动态计算属性
const calculator = {
factor: 2
};
const proxy = new Proxy(calculator, {
get(target, prop) {
if (prop === "double") {
return target.factor * 2;
}
return target[prop];
}
});
console.log(proxy.factor); // 输出: 2
console.log(proxy.double); // 输出: 4
总结
Proxy 提供了一种灵活的方式来拦截和自定义对象的行为,适用于以下场景:
- 数据验证与保护
- 动态属性计算
- 日志记录或调试
- 实现代理模式或权限控制
通过 Proxy
,可以让代码更具可读性和功能性,同时也需要注意避免过度复杂的拦截逻辑。