如何检测表单验证函数是否访问了表单模型参数
如何检测表单验证函数是否访问了表单模型参数
这个需求特别实际——要是验证器根本没用到表单模型的数据,那模型变化时确实没必要重复跑验证,能省下不少不必要的性能开销。我给你推荐一个精准又可行的方案,基于Proxy来追踪模型是否被访问,而且它的开销远没有你担心的那么大~
具体实现思路
核心逻辑就是用Proxy包装你的表单模型,当任何验证器访问模型的属性时,我们就标记“模型已被访问”。这种方式能精准识别实际用到模型数据的验证器,哪怕验证器声明了第二个参数但完全没使用它,也不会误判。
修改后的完整代码如下:
const formModel = { firstname: 'Bill', lastname: 'Gates', departureDate: new Date(), returnDate: new Date() }; const value = 'Test'; const nonAccessValidators = [ v => v ? null : 'required', v => v?.length ?? 0 > 1 ? null : 'incomplete' ]; const accessValidators = [ v => v ? null : 'required', (v, m) => v > m.departureDate ? null : 'before-date' ]; const runValidators = (value, formModel, validators) => { let formModelAccessed = false; // 创建Proxy追踪模型的属性访问 const trackedModel = new Proxy(formModel, { get(target, prop) { // 只要访问了模型的任意属性,就标记为已访问 formModelAccessed = true; return target[prop]; }, // 兜底处理设置属性的情况(验证器一般只读,但留个保险) set() { formModelAccessed = true; return true; } }); const errors = validators.reduce((acc, validator) => { const error = validator(value, trackedModel); if (error) { acc.push(error); } return acc; }, []); return { formModelAccessed, errors }; }; const nonAccessErrors = runValidators(value, formModel, nonAccessValidators); const accessErrors = runValidators(value, formModel, accessValidators); // 测试结果: // nonAccessErrors -> { formModelAccessed: false, errors: [] } // accessErrors -> { formModelAccessed: true, errors: ['before-date'] }
方案细节说明
- 精准追踪访问行为:只有当验证器真正读取(或写入)模型的属性时,才会触发Proxy的拦截逻辑,把
formModelAccessed设为true。像那种只接收第二个参数但完全不用它的验证器,不会触发标记,完全符合你的需求。 - 性能开销可忽略:Proxy是浏览器原生支持的高效特性,创建和运行的成本极低,哪怕每次模型变化都创建新的Proxy,在实际业务场景中也几乎不会有性能感知。
- 兼容性友好:Proxy在所有现代浏览器和Node.js环境都能正常运行,除非你需要兼容IE这类超老环境,否则完全不用顾虑兼容性问题。
不推荐的替代方案
比如通过validator.toString()解析函数体来判断是否引用第二个参数,这种方法很容易失效:
- 代码压缩后参数名会被混淆(比如变成
(a,b)=>...),无法准确识别; - 函数如果是通过bind、高阶函数等方式创建的,toString的结果可能不符合预期;
- 无法区分“声明了参数但未使用”和“实际使用参数”的情况。
所以Proxy的方案是目前最靠谱的选择。
备注:内容来源于stack exchange,提问作者Adrian Brand
相关产品推荐
相关产品推荐

