深拷贝确保表单校验规则各实例完全隔离,避免嵌套结构、函数引用、Symbol属性等导致的意外共享;推荐优先用structuredClone,兼容环境则降级为支持函数/Symbol/循环引用的手写轻量深拷贝。

在复杂表单动态校验规则生成场景中,深拷贝不是为了“备份数据”,而是确保每组验证配置(如不同字段、不同条件分支、不同嵌套层级的 rule 对象)彼此完全隔离——改一个字段的 rules,不能意外影响另一个字段、另一个 tab 页、或另一个重复项里的同名 rule。
为什么浅拷贝在这里会出问题
表单校验规则常是嵌套结构,比如:
- 多层嵌套:rule.required、rule.pattern、rule.validator(函数)、rule.message(含插值)、rule.trigger、甚至 rule.asyncValidator
- 动态组合:根据用户选择切换整套规则(如“身份证” vs “手机号”),或为数组字段(如 contacts)批量生成独立 rule 实例
- 含非纯数据类型:validator 是函数;message 可能含闭包引用;某些 UI 框架的 rule 还带 Symbol 属性或不可枚举元信息
用 Object.assign({}, rule) 或 {...rule} 只复制顶层属性。一旦 rule 里有 validator: (v) => {...} 或 deps: ['userType'] 这样的引用型字段,多个表单项就会共享同一 validator 函数或同一 deps 数组——修改其中一个的 validator 内部状态(比如缓存),其他字段也会被波及。
推荐方案:优先用 structuredClone + 降级兜底
现代项目(Chrome 98+/Firefox 94+/Safari 15.4+)可直接用 structuredClone,它天然支持:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- Date、RegExp、Map、Set、ArrayBuffer(虽校验规则不常用,但扩展性好)
- 循环引用(防止配置里意外出现 self-reference)
- 保留原型链和可枚举性(对部分框架的 rule 类实例友好)
兼容旧环境时加简单降级:
function cloneRule(rule) {
if (typeof structuredClone === 'function') {
try {
return structuredClone(rule);
} catch (e) {
// fallback to JSON method only if rule is pure data
if (isPlainJsonSafe(rule)) {
return JSON.parse(JSON.stringify(rule));
}
}
}
return deepCloneFallback(rule); // 手写基础版(见下文)
}
手写轻量深拷贝(适配校验规则特点)
多数校验规则不含 Map/Set/ArrayBuffer,但需保留函数、Symbol 键、Date(如 message 中的时间模板)、以及避免循环引用。可用以下精简实现:
function deepCloneFallback(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
// 保留函数、正则、日期、数组、普通对象
let cloned;
if (obj instanceof Date) cloned = new Date(obj);
else if (obj instanceof RegExp) cloned = new RegExp(obj);
else if (Array.isArray(obj)) cloned = [];
else cloned = Object.create(Object.getPrototypeOf(obj));
seen.set(obj, cloned);
// 复制所有自有属性(包括 Symbol 键)
const keys = [...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)];
for (const key of keys) {
const desc = Object.getOwnPropertyDescriptor(obj, key);
if (desc.enumerable || key typeof Symbol === 'symbol') {
cloned[key] = deepCloneFallback(obj[key], seen);
}
}
return cloned;
}
这个版本不丢函数、不丢 Symbol、能破循环引用,体积小,适合嵌入表单工具函数中。
实际使用建议
- 不要在每次 input 触发时深拷贝整个 rule 树——只在 rule 配置变更、tab 切换、或新增数组子项时拷贝
- 对 validator 函数,若需定制上下文(如绑定 this 或注入 formInstance),拷贝后单独做
.bind()或闭包封装,而非依赖深拷贝处理函数体 - 若用 Ant Design / Element Plus 等框架,其
rules属性本身支持响应式更新,深拷贝后应触发对应字段的 rule 重置(如调用form.validateFields(['name']))

















