2026年了,表单里日期选完保存总提示格式不对,是深拷贝把 Date 变成字符串了吗?
结论先放前面:JSON.parse(JSON.stringify(obj)) 只有在数据完全由 JSON 支持的类型组成时才等价,也就是对象、数组、字符串、数字、布尔值和 null。一旦出现 Date、undefined、函数、Symbol、NaN 或循环引用,它不会提醒你,而是静默改值或直接抛错。2026 年项目联调里,日期字段在弹窗里显示正常、保存时却提示格式不对,根因往往不是接口,而是拷贝方式选错了。
为什么时间字段会变成字符串
JSON 往返本质是一次序列化加解析,不是一次完整的对象克隆。JSON.stringify 把值翻译成文本,JSON.parse 再按 JSON 语法读回来。JSON 语法里没有时间对象、函数、Map,这些类型在翻译过程中就被替换或丢弃。所以拿到的虽然是一个新引用,字段类型却已经和原来不是一回事。
这个过程分两段损失:序列化阶段,值必须按 JSON 语法表达,表达不了的就转换或跳过;解析阶段,文本只能还原成 JSON 能表达的类型,无法还原原型链、方法或类型标记。字符串「2026-01-01T00:00:00.000Z」和 Date 在业务里完全不是一回事,只差一个类型,排查方向就偏了。
哪些值会在这圈里变样
按 2026 年常见交付经验,下面几类在中后台、订单、日程、报表项目里出现频率较高,也容易被误判成后端返回有问题。建议在接口契约评审时,把时间、金额、枚举这几类字段的类型写清楚,而不是等联调现场再猜。
- Date:变成 ISO 格式字符串,getTime、getFullYear 等方法需要先转回时间对象才能用。
- undefined、函数、Symbol:作为对象属性时整个键被丢掉,出现在数组里则变成 null。
- NaN、Infinity、-Infinity:统一变成 null,数值含义被改写,统计类页面容易算错。
- Map、Set、RegExp、Error:结构丢失或变成空对象,集合类数据的顺序与键值关系无法还原。
- 循环引用:序列化阶段直接抛错,问题往往到运行时才炸。
- 类实例:原型方法全部丢失,只剩下可枚举的自有属性。
可核对对比:几种深拷贝方式怎么选
2026 年比较稳妥的做法是按数据复杂度分层使用,而不是全项目统一一种写法。下面这组对比可以当作内部约定的起点,具体选择还要看运行环境和数据形态。
- JSON 往返:实现成本低,适合纯 JSON 数据(配置、纯文本草稿、结构固定的表单数据);不支持 Date、Map、Set、函数和循环引用。常见区间:纯数据场景几十分钟内可铺开,但一旦有非 JSON 类型,后续排查可能拖到数小时甚至数天(经验区间)。
- structuredClone:原生结构化克隆,支持 Date、Map、Set、ArrayBuffer 和循环引用;不支持函数、Symbol、DOM 节点,也不保留类原型。2026 年主流浏览器与较新 Node 运行时已可用,常见做法是先按运行环境清单核对支持情况。常见区间:替换成本约一处工具函数,半天内可完成回归。
- 手写递归拷贝:可控性强,可按业务规则处理特殊类型;实现与维护成本偏高,适合有明确类型约定的领域对象。常见区间:首版实现半天到两天,后续每加一种类型都要补测试。
- 第三方工具库:覆盖面广、省事,代价是引入体积与后续升级维护,适合已有依赖或类型特别复杂的场景。
对比时可以看六个维度:支持的类型范围、是否处理循环引用、是否保留原型、实现成本、长期可维护性,以及在目标端与目标运行环境下的兼容表现。对多数业务项目来说,把「纯 JSON 数据」和「带时间或集合的数据」分开走两条路,通常比追求一种通用写法更好验收。
交付现场:日期选完保存提示格式不对,先查拷贝方式
在一次中后台订单编辑弹窗联调中,列表页把接口返回的订单对象用 JSON 往返拷进表单,弹窗里的日期选择器绑定时间对象。页面打开时日期显示正常,用户改完一点保存,接口返回「时间格式不合法」。当时的约束很清楚:周期紧,通常一两天内要上线;接口文档只写了「时间」没标类型;素材侧也没有可对照的示例数据。可行做法是先只替换拷贝方式,不动业务逻辑,测试环境定位加修复常在半天量级;如果把 JSON 往返当成通用深拷贝铺到整个项目,后面每个涉及时间的模块都要重查一遍,返工成本会从半天扩到数天(经验区间)。拷贝方式属于接口契约的一部分,不该只在某个页面里悄悄决定。
适用与不适用边界:什么时候该深拷贝,什么时候不用
深拷贝不是越保险越好,它是有开销的手段。判断标准可以落在一句话上:副本和原数据会不会同时被修改,且两边的修改语义不同。如果是,才需要隔离;如果只是只读展示,直接引用反而更省内存。
- 适合深拷贝:编辑弹窗把接口数据放进表单,用户取消时原列表不能变;撤销重做、草稿箱这类要保留多份历史状态的场景。
- 不必深拷贝:只读列表和详情展示直接引用接口数据即可;只在首层增删字段时浅拷贝就够;采用不可变更新方式的代码本来就产生新对象。
- 明确不适用:数据里含 Date、Map、Set、循环引用或类实例时,JSON 往返不适合;只需要隔离首层时上深拷贝,只会增加开销和排查量。
常见问题
JSON 深拷贝后 undefined 丢了,接口还要这个字段怎么办?
JSON 语法里没有 undefined,该键会被直接删掉。要么在拷贝后按字段补回默认值,要么改用结构化克隆或手写拷贝保留该键。
structuredClone 在 2026 年能放心用吗?
2026 年主流浏览器和较新 Node 运行时已支持常规对象、数组、Date、Map、Set 与循环引用;函数和 DOM 节点仍不支持,先按运行环境清单核对。
展开运算符 {...obj} 算深拷贝吗?
不算,它只复制首层。第二层仍是同一个引用,改副本的第二层会连带改到原对象,这也是联调里常见的「改了副本原数据也变」。
接口返回的数据要不要先深拷贝再用?
只读展示不需要。进表单编辑、要保留原始值做对比或撤销时才建议拷贝,并优先选支持时间对象的拷贝方式。
深拷贝之后只改副本,原对象还是变了,该从哪查?
先确认第二层以下是不是还在共享引用,再看别处有没有直接改原对象。多数情况是拷贝层次不够,或两个变量其实指向同一个数据源。
动手前先问一句:这份数据里有 Date、undefined、Map 或循环引用吗?有就别用 JSON 往返;没有,它在纯 JSON 数据上确实是成本较低的深拷贝写法。若数据只在首层被修改,浅拷贝即可,不必为「保险」付性能代价。适用边界:跨端、全栈以及金额、时间敏感的字段,建议在接口契约里明确类型,并在验收清单中核对拷贝后的类型一致性。
-
2026年了,对象复制后为什么修改第二层,原对象也跟着变?
日期:2026年9月6日 阅读:168
-
2026年了,Uni-app 打的 App 一提审就说隐私弹窗没前置,我明明弹了,是 SDK 先跑了吗?
日期:2026年10月15日 阅读:45
-
Flutter 嵌的 H5 活动页,安卓上滑动发涩,到底该先动哪一层?
日期:2026年10月14日 阅读:60
-
2026年了,页面 title 在源码里看不到,百度收录的标题是从哪来的?
日期:2026年10月13日 阅读:54
-
Angular 里 OnPush 子组件接轮询数据不刷新,先换数组引用还是先补 markForCheck?
日期:2026年10月12日 阅读:70




