json.parse(json.stringify(obj))并非真正深拷贝:会丢失函数/undefined/symbol,date变字符串,regexp变{},循环引用报错,不支持bigint、nan/infinity转null等。

用 JSON.parse(JSON.stringify(obj)) 是 JS 中实现**简单深拷贝**的常用技巧,但它有明确的适用边界——只适用于纯数据对象(即只含字符串、数字、布尔值、null、数组、普通对象),不支持函数、undefined、Symbol、Date、RegExp、Map、Set、BigInt 等类型。
它为什么能“深拷贝”?
因为 JSON.stringify() 会把对象序列化为字符串,这个过程天然跳过不可序列化的属性(如函数、undefined),也把嵌套结构“扁平化”成文本;再用 JSON.parse() 解析回来,就生成了一个全新内存地址、结构一致的新对象,实现了对可序列化部分的深拷贝。
哪些情况会出问题?
-
丢失函数和 undefined:方法被忽略,undefined 值变成 null 或直接消失(如
{a: undefined, b: 1}→{"b":1}) -
Date 变成字符串:如
new Date()→"2024-05-10T08:30:00.000Z",不再是 Date 实例 -
正则表达式变空对象:
/abc/g→{} -
循环引用直接报错:
const a = {}; a.self = a;→TypeError: Converting circular structure to JSON - Symbol 和 BigInt 被忽略或报错:Symbol 键名丢失;BigInt 在 stringify 时抛错
什么时候可以用?
适合处理配置项、API 返回的纯数据响应、表单初始值等场景。例如:
const original = {
name: "Alice",
scores: [95, 87, 91],
address: { city: "Beijing", zip: "100000" }
};
const copied = JSON.parse(JSON.stringify(original));
copied.address.city = "Shanghai";
console.log(original.address.city); // "Beijing" —— 原对象未被修改
更稳妥的替代方案
如果数据结构复杂,建议用:
- structuredClone()(现代浏览器 & Node.js 17.0+):原生支持 Map/Set/Date/RegExp,且能处理循环引用(但暂不支持函数、undefined、Symbol)
- Lodash 的 _.cloneDeep():兼容性好,覆盖类型最全(含函数、undefined 等,按需序列化)
- 自定义递归拷贝:可控性强,但需手动处理各种边界类型











