前端开发者每天都要和各种对象打交道,但你是否想过给对象装上"监控摄像头"?Proxy 就是这样一个神奇的存在------它能让你在对象的一举一动上安装监听器,实现真正的"上帝视角"。本文将用 5 个真实场景 + 7 个核心用法,带你彻底掌握这个 ES6 的终极武器。
一、初识 Proxy:对象世界的"智能管家"
1.1 什么是 Proxy?
想象你有一个贴身管家(Proxy),每当有人要接触你的物品(对象)时,管家都会先询问你的意见。Proxy 就是这样一个中介层,允许你拦截并自定义对象的底层操作。
javascript
const person = { name: '小明' };
const guardian = new Proxy(person, {
get(target, property) {
console.log(`有人想获取 ${property} 属性`);
return target[property];
}
});
console.log(guardian.name); // 输出:有人想获取 name 属性 → 小明
1.2 创建基础 Proxy
Proxy 构造函数接收两个参数:
javascript
const proxy = new Proxy(target, handler);
target
: 要代理的目标对象handler
: 定义拦截行为的"陷阱"对象
二、Proxy 的七大核心陷阱
2.1 属性访问拦截(get)
javascript
const bankAccount = new Proxy({ balance: 1000 }, {
get(target, prop) {
if (prop === 'balance') {
console.warn('余额查询需授权');
return '***';
}
return target[prop];
}
});
console.log(bankAccount.balance); // 输出警告并返回***
2.2 属性设置拦截(set)
javascript
const validator = new Proxy({}, {
set(target, prop, value) {
if (prop === 'age' && !Number.isInteger(value)) {
throw new Error('年龄必须是整数');
}
target[prop] = value;
return true; // 必须返回true表示成功
}
});
validator.age = 30; // 正常
validator.age = '三十'; // 抛出错误
这个Proxy
就是保证对应基本类型。
2.3 函数调用拦截(apply)
javascript
const logger = new Proxy(function sum(a, b) {
return a + b;
}, {
apply(target, thisArg, args) {
console.log(`正在计算 ${args.join('+')}`);
return target(...args);
}
});
logger(2, 3); // 输出日志 → 5
这个 Proxy
对象拦截了对 sum
函数的调用,在调用函数之前输出了一条日志信息,然后执行原函数并返回结果。通过这种方式,我们可以在不修改原始函数代码的情况下,为函数添加额外的功能,比如日志记录、性能监控等。
2.4 其他常用陷阱

三、Proxy 的五大实战场景
3.1 数据验证器
javascript
const userValidator = new Proxy({}, {
set(target, prop, value) {
const rules = {
username: v => v.length >= 3,
password: v => /[A-Z]/.test(v),
email: v => v.includes('@')
};
if (rules[prop] && !rules[prop](value)) {
throw new Error(`${prop} 格式错误`);
}
target[prop] = value;
return true;
}
});
3.2 自动缓存系统
javascript
function createCache(fn) {
const cache = new Map();
return new Proxy(fn, {
apply(target, thisArg, args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('命中缓存');
return cache.get(key);
}
const result = target(...args);
cache.set(key, result);
return result;
}
});
}
3.3 表单自动保存
javascript
const formData = new Proxy({}, {
set(target, prop, value) {
target[prop] = value;
autoSaveToLocalStorage();
return true;
}
});
// 每次修改自动触发保存
formData.username = 'Alice';
四、Proxy 的进阶技巧
4.1 链式操作拦截
javascript
const chain = new Proxy({}, {
get(target, prop) {
return (...args) => {
console.log(`执行 ${prop} 操作,参数:${args}`);
return new Proxy({}, this); // 返回新代理实现链式调用
};
}
});
chain.add(5).subtract(3).multiply(2);
4.2 不可变对象
javascript
function createImmutable(obj) {
return new Proxy(obj, {
set() { throw new Error('不可修改'); },
deleteProperty() { throw new Error('不可删除'); }
});
}
五、Proxy 的注意事项
- 性能损耗:频繁操作时需谨慎使用
- 浏览器兼容:IE 全系不支持,移动端需注意
- 无法代理特殊对象 :如
Date
,Map
,Set
等需要特殊处理 - 代理的代理:多层代理可能产生意外行为
六、Proxy vs Object.defineProperty
特性 | Proxy | Object.defineProperty |
---|---|---|
拦截范围 | 13种操作 | 仅属性读写 |
数组处理 | 完美支持 | 需要hack处理 |
动态属性 | 自动捕获 | 需要预先定义 |
代码侵入性 | 无 | 需要修改对象 |
性能 | 稍慢 | 更快 |
掌握 Proxy 就像获得了一把打开元编程大门的钥匙。建议读者从简单的数据验证开始实践,逐步探索更复杂的应用场景。记住:能力越大责任越大,合理使用才能发挥其真正价值。