JavaScript 深拷贝与正则校验:数据边界、Unicode 和输入契约
本文目录
“深拷贝”没有脱离数据模型的万能实现。先确认需要复制的值种类、循环引用、函数/类实例、DOM 和传输边界,再决定使用结构化克隆、领域映射或序列化;不要把递归复制任意对象当成安全通用工具。
浅拷贝与结构化克隆
展开运算符和 Object.assign 只复制一层属性值;嵌套对象仍共享引用。浏览器 structuredClone 能复制结构化克隆算法支持的多种值并可处理循环引用,但不会保留原型链、函数、DOM 节点、属性描述符或自定义类语义;不支持的值可能抛错。带 Transferable 的迁移会移动底层资源而非普通复制,要先确认原对象之后不再使用。
JSON 往返只适合明确受限的 JSON 数据。它会丢掉函数、undefined、Symbol、Map/Set 和原型信息,日期会变成字符串,循环引用会报错,特殊数字会发生转换。把 JSON 序列化当成“任意对象安全深拷贝”会制造静默数据变化。
const original = {
settings: { theme: 'dark' },
createdAt: new Date(),
};
const shallow = { ...original };
shallow.settings === original.settings; // true
const copy = structuredClone(original);
copy.settings === original.settings; // false
copy.createdAt instanceof Date; // true
如果只需更新一条数据,通常用局部不可变更新比复制整棵对象树更简单。来自网络或用户输入的数据要做 schema 验证、字段白名单和尺寸限制,而不是依赖克隆来净化。
正则表达式先定义格式
RegExp 适合检查明确的字符串形态,不适合替代语义验证。验证整串时使用起止边界并限制长度;如果同一个正则对象带 g 或 y,test/exec 会修改 lastIndex,重复校验可能出现交替结果。需要重复使用的格式校验时避免全局标志。
身份证、邮箱和姓名等格式受国家、产品规则、国际化与法规影响。固定一个 ASCII 邮箱正则不能证明地址存在、可收信或属于用户;邮箱验证应通过一次性验证流程确认控制权。证件号规则要按目标地区官方规则和业务范围设计,并在服务端重新验证,不要从旧题库复制宽松或过时模式。
function isAsciiIntegerText(value) {
return typeof value === 'string'
&& value.length <= 12
&& /^-?\d+$/.test(value);
}
function parseWholeQuantity(value) {
if (typeof value !== 'string' || !/^(0|[1-9]\d{0,5})$/.test(value)) return null;
const number = Number(value);
return Number.isSafeInteger(number) ? number : null;
}
Unicode 正则中的 \d 通常针对 ASCII 数字语义;需要国际数字字符时先确认需求并采用 Unicode 属性转义和支持该语法的运行环境。不要仅靠正则做完整邮箱、电话、地址或身份判断。
回归样例
为空值、首尾空格、正负号、小数点、换行、全角数字、超长字符串、emoji、重复调用带 g 的 RegExp、循环引用和 Date/Map 分别写测试。说明哪些数据允许规范化、哪些应拒绝;服务器响应错误要可读且不泄露内部校验细节。
参考:MDN structuredClone、MDN structured clone algorithm、MDN Regular expressions、MDN RegExp.test、MDN Object.assign。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。