json.parse(json.stringify(obj)) 会丢失 undefined,因 json.stringify 忽略 undefined 属性,数组中则转为 null;可用 deepclone 递归函数或现代 structuredclone api 保留 undefined。

JavaScript 中用 JSON.parse(JSON.stringify(obj)) 做深拷贝时,undefined、function、Symbol、BigInt 和循环引用都会被静默丢弃或报错——undefined 是其中最常被忽略的问题之一,因为它不会报错,但值直接消失。
为什么 JSON 方法会丢失 undefined
JSON.stringify() 的规范明确规定:对象中值为 undefined、function 或 Symbol 的属性会被**完全忽略**(不序列化),数组中遇到 undefined 则转为 null。所以后续 JSON.parse() 根本看不到它。
- 对象:
{ a: 1, b: undefined }→"{"a":1}"(b键彻底消失) - 数组:
[1, undefined, 3]→"[1,null,3]"(变成null,不是undefined)
替代方案:手写递归拷贝(保留 undefined)
若必须保留 undefined,且不依赖第三方库,可写一个轻量递归函数,显式处理所有类型,包括 undefined:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
const cloned = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]); // undefined 会被原样赋值
}
}
return cloned;
}
这个版本能准确保留 undefined、null、原始值和嵌套结构,但不处理 Date、RegExp、Map、Set 等特殊对象,也不解决循环引用。
更稳妥的做法:用 structuredClone(现代浏览器 & Node.js 17+)
structuredClone() 是浏览器和新版 Node.js 提供的原生深拷贝 API,支持 undefined、BigInt、Date、RegExp、ArrayBuffer 等,且自动处理循环引用(只要值可结构化)。
- ✅ 支持
undefined:structuredClone({ a: 1, b: undefined })返回完整对象 - ✅ 安全:不执行代码,无 XSS 风险
- ⚠️ 注意:不支持
function、Symbol、Promise等非结构化值(会抛错)
使用前建议加个检测:
if (typeof structuredClone === 'function') {
const copy = structuredClone(original);
} else {
console.warn('structuredClone not supported, fallback needed');
}
如果必须用 JSON 方案,怎么“模拟”保留 undefined
没有完美办法,但可约定一种标记策略(仅限可控场景):
- 预处理:把
undefined替换成一个特殊占位符,如"__UNDEFINED__" - 序列化后解析,再把占位符还原为
undefined
示例:
function jsonCloneWithUndefined(obj) {
const placeholder = '__UNDEFINED__';
const str = JSON.stringify(obj, (key, val) =>
val === undefined ? placeholder : val
);
return JSON.parse(str, (key, val) =>
val === placeholder ? undefined : val
);
}
⚠️ 注意:该方法要求数据中**不能出现字符串 "__UNDEFINED__"**,否则会被误还原;也不适用于函数或循环引用。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











