proxy 是 javascript 中用于拦截和自定义对象操作的中间层机制,核心由 target 和 handler 构成,支持 get、set、has、apply、ownkeys 等 trap 拦截读写调用等行为,需注意 reflect 转发、浅层代理及私有字段限制。

Proxy 是 JavaScript 中专为拦截和自定义对象操作而生的机制,它不修改原对象,而是在访问路径上加一层可控的“中间层”。只要目标是对象(或函数、数组等可代理类型),你就能通过 handler 里的各种 trap 精准捕获读、写、调用、枚举等行为。
核心结构:target + handler 缺一不可
创建 Proxy 必须传入两个参数:
- target:原始对象,可以是普通对象、函数、数组,甚至另一个 Proxy;但不能是 null、undefined、原始值(如字符串字面量)
- handler:一个配置对象,里面定义了各类“陷阱”(trap)函数,比如 get、set、apply。每个 trap 对应一种底层操作,触发即执行
例如:const proxy = new Proxy({ x: 1 }, { get() { console.log('被读取了'); } }); —— 每次访问 proxy.x 都会打印日志。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
高频拦截场景与对应 trap
日常开发中真正用得多的 trap 并不多,掌握以下五个就能覆盖绝大多数需求:
- get(target, prop, receiver):拦截属性读取,可用于默认值兜底、私有字段保护、响应式依赖收集
- set(target, prop, value, receiver):拦截赋值,适合数据校验(如邮箱格式)、只读控制、变更通知
-
has(target, prop):拦截
prop in proxy,可隐藏某些属性不让in检测到 -
apply(target, thisArg, args):仅当 target 是函数时生效,拦截
proxy()调用,常用于函数增强、缓存、埋点 -
ownKeys(target):拦截
Object.keys()、for...in、Reflect.ownKeys(),能动态过滤或注入键名
实用技巧:避免踩坑的关键细节
Proxy 看似简单,但几个细节处理不好会导致逻辑失效或难以调试:
- 在
get和set中务必使用Reflect.get(target, prop, receiver)或Reflect.set(...)转发默认行为,否则继承链、this 绑定、getter/setter 可能异常 - Proxy 只代理第一层,嵌套对象不会自动被代理。需要递归包装或按需代理(例如 Vue3 响应式系统就是逐层代理)
- 无法拦截私有字段(#field)、Symbol 属性若未显式定义在 handler 中也不会被 get/set 捕获,需额外处理
- 对 Map/Set 等集合,要拦截的是其方法(如
set.add()),得在gettrap 中识别并包装原生方法,而非直接监听属性变化
真实可用的小例子:带邮箱校验的用户对象
下面这个 proxy 会在设置 email 时自动校验格式,非法值直接拒绝,并保留其他字段自由操作:
const user = { name: '李四' };
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const validatedUser = new Proxy(user, {
set(target, key, value) {
if (key === 'email' && !emailRegex.test(value)) {
console.warn('邮箱格式错误,未保存');
return false; // 阻止赋值
}
target[key] = value;
return true;
},
get(target, key) {
return key in target ? target[key] : '暂无信息';
}
});
validatedUser.email = 'invalid-email'; // 控制台警告
validatedUser.email = 'test@example.com'; // 成功
console.log(validatedUser.email); // 'test@example.com'
console.log(validatedUser.age); // '暂无信息'










