表单草稿箱必须用深拷贝,以确保嵌套结构(如地址组、文件元数据、日期对象)完整存入localStorage且还原时不丢失类型或引发引用污染;优先用structuredClone(),不支持时回退JSON序列化并过滤非安全字段。

在表单草稿箱场景中做深拷贝,核心目标不是“为了深拷贝而深拷贝”,而是确保用户输入的嵌套结构(如动态添加的地址组、多文件元数据、带日期/对象的配置项)能完整、安全地存入 localStorage,且后续还原时不丢失类型语义或引发引用污染。
为什么表单草稿必须用深拷贝?
表单数据常含嵌套对象(如 {user: {profile: {name: '', avatar: null}, contacts: [...]}})。若只用浅拷贝(如展开运算符或 Object.assign)保存到草稿变量,后续修改表单时可能意外改写原始草稿快照;更严重的是,直接把表单 DOM 元素引用或临时状态对象存进 localStorage 会失败——因为 localStorage 只接受字符串。
选对深拷贝方法:优先 structuredClone + JSON 回退
现代浏览器(Chrome 98+、Firefox 94+、Safari 15.4+)推荐用 structuredClone() 做初始深拷贝,它天然支持 Date、Map、Set、RegExp 和循环引用,且不丢属性:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
-
适用场景:表单含时间选择器(生成
Date)、标签管理(用Set去重)、正则校验规则等 -
注意限制:不能存
function、undefined、Symbol、Promise—— 表单数据本就不该含这些,可提前过滤 -
兼容降级:若需支持旧浏览器,检测
typeof structuredClone === 'function',否则回退到JSON.parse(JSON.stringify()),但要先清理非 JSON 安全字段(如移除Date对象并转为 ISO 字符串)
存入 localStorage 的关键处理步骤
深拷贝只是中间环节,真正持久化需结合序列化与键管理:
立即学习“Java免费学习笔记(深入)”;
-
过滤不可存字段:删除
__v、id(后端生成)、isDirty等运行时标记属性,避免污染草稿语义 -
统一时间格式:将
Date实例转为toISOString()字符串,既保留时区信息,又确保 JSON 兼容 -
使用唯一存储键:按表单 ID 或用户+页面路径生成 key(如
draft-form-profile-uid123),避免多个表单互相覆盖 -
写入前校验大小:
localStorage通常限 5–10MB,大附件元数据建议单独存 IndexedDB,草稿只留轻量结构
还原草稿时也要深拷贝
从 localStorage 读出的是字符串,JSON.parse() 后得到的是新对象,但它仍是“浅层独立”的——如果原表单逻辑依赖某个共享配置对象,直接赋值仍可能造成后续修改污染。稳妥做法是:
- 读取后立即用
structuredClone()再拷一份(尤其当草稿会被多次编辑并暂存) - 或在还原函数里封装成
loadDraft(formId),内部自动执行深拷贝再合并到当前表单响应式数据 - 避免直接
formState = JSON.parse(stored),防止后续formState.items.push(...)意外影响本地存储副本

















