proxy 的 set 拦截器只捕获目标对象自身属性赋值,不递归拦截嵌套对象(如 form.user.name),需惰性代理:get 中对 object 类型子属性自动包装 proxy,set 中校验当前字段并递归 wrap 新 object 值,用 weakmap 缓存避免重复代理。

为什么直接用 set 拦截器无法捕获嵌套对象的赋值?
Proxy 的 set trap 只对目标对象自身的属性赋值生效,不会递归拦截深层属性。比如 form.user.name = "alice" 中,若 user 是普通对象,set 只会触发在 form 上,而 user.name 的赋值完全绕过 Proxy —— 这导致校验逻辑漏掉关键字段。
解决办法是:所有嵌套值也必须是 Proxy 实例。但不能一上来就全递归代理(性能差、循环引用崩溃),而是「惰性代理」—— 在第一次访问或赋值子属性时,才对对应子对象创建 Proxy。
- 用
gettrap 拦截属性读取,对返回的 object 类型值自动包装为带校验的 Proxy - 用
settrap 校验当前层级字段,再判断新值是否为 object,是则递归 wrap - 需缓存已代理的对象,避免重复代理同一对象(用
WeakMap)
set 中如何统一做字段校验而不侵入业务逻辑?
校验规则不应硬编码在 Proxy 里,而应从外部声明式传入。推荐把校验逻辑抽成独立函数,按字段名映射:
const rules = {
email: (v) => typeof v === 'string' && v.includes('@'),
age: (v) => Number.isInteger(v) && v >= 0 && v Array.isArray(v) && v.length
<p>在 <code>set</code> trap 中,先查 <code>rules[key]</code>,有则执行;失败时抛错或静默记录(取决于表单场景)。注意:校验应在赋值前进行,否则脏数据已写入。</p>
- 校验函数返回
true或错误信息字符串,便于上层收集全部错误 - 对未声明规则的字段,默认放行(避免阻断未知字段扩展)
- 若字段值为
null或undefined,需单独判断是否允许空值(可加required: true配置)
如何让校验结果实时可读且支持批量获取?
用户需要知道「哪些字段错了」「错在哪」,所以不能只靠 throw 报错。建议在 Proxy 目标对象上挂一个隐藏状态对象,比如 $$errors,由 Proxy 自动维护:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
const form = new Proxy(
{ $$errors: {} },
{
set(target, key, value) {
if (key === '$$errors') return false; // 禁止手动改 errors
const error = validate(key, value);
target.$$errors[key] = error || null;
// … 继续赋值逻辑
return true;
}
}
);
这样调用方随时可读 form.$$errors.email,也可遍历 Object.keys(form.$$errors) 汇总全部问题。注意:$$errors 必须是自有属性,不能放在原型上,否则 in 操作符和 for...in 会污染结果。
- 每次
set后只更新当前字段错误,不重算全量(性能友好) - 提供
form.validateAll()方法主动触发所有字段校验(用于提交前兜底) - 若字段被设为合法值,对应
$$errors[key]应清空(设为null),而非删除键(避免响应式框架误判)
IE11 兼容性与 Proxy 替代方案的现实取舍
Proxy 是 ES2015+ 特性,IE11 完全不支持。如果项目必须兼容 IE11,不要试图 polyfill Proxy(不可行),而应降级为 Object.defineProperty + 递归遍历初始化。
但要注意:defineProperty 无法监听新增属性(form.newField = 1 不触发),也无法监听数组索引赋值(arr[0] = x)。这意味着:IE11 下只能校验「初始定义时已知的字段」,动态字段和数组操作会静默失效。
- 可在构建时通过 Babel 插件自动注入 defineProperty 逻辑,但需提前枚举所有字段路径
- 更务实的做法是:检测
typeof Proxy === 'function',不支持时降级为纯函数校验(提交时集中校验,放弃实时反馈) - 即使使用 Proxy,也要避免在
get/set中做重操作(如深克隆、正则全局匹配),否则表单滚动或输入会卡顿
真正难的不是写完一个能跑的 Proxy 表单模型,而是决定哪些字段值得实时校验、哪些留到提交时检查,以及如何让错误提示既及时又不干扰用户输入节奏。










