← 返回题目列表

JSON.stringify 和 JSON.parse 有哪些细节和限制?

中等 第 25 / 29 题 更新于 2026/07/29
JavaScriptJSON序列化

简化版

JSON.stringify 把 JavaScript 值转成 JSON 字符串,JSON.parse 把 JSON 字符串解析成值。它们只适合 JSON 支持的数据:对象、数组、字符串、数字、布尔值和 null

函数、undefinedSymbol、循环引用、BigInt 等都要特别处理。对象里这些值通常会被忽略,数组里会变成 null,循环引用会直接抛错。

详细版

常见行为:

JSON.stringify({
  a: undefined,
  b: () => {},
  c: Symbol("x"),
  d: null
});
// {"d":null}

JSON.stringify([undefined, () => {}, Symbol("x")]);
// [null,null,null]

循环引用会报错:

const obj = {};
obj.self = obj;
JSON.stringify(obj); // TypeError

JSON.stringify 支持 replacerspaceJSON.parse 支持 reviver

const text = JSON.stringify({ password: "x", name: "Ada" }, (key, value) => {
  return key === "password" ? undefined : value;
}, 2);

const data = JSON.parse('{"createdAt":"2026-07-29"}', (key, value) => {
  return key === "createdAt" ? new Date(value) : value;
});

完整版教学

一、JSON 不是 JavaScript 对象的完整镜像

JSON 是一种数据交换格式,不是 JavaScript 内存对象的完整快照。

它支持的数据类型很有限:

JSON 类型JavaScript 对应值
object普通对象
array数组
string字符串
number有限数字
boolean布尔值
nullnull

函数、原型、访问器属性、MapSetDate 的对象身份都不会被完整保留。

看到 JSON 序列化,要立刻想到“跨进程传数据”,不是“深拷贝一切”。

二、对象和数组里特殊值表现不同

对象属性中,undefined、函数、Symbol 会被忽略。

const obj = {
  a: 1,
  b: undefined,
  c() {},
  d: Symbol("d")
};

console.log(JSON.stringify(obj)); // {"a":1}

数组元素中,这些值会变成 null

console.log(JSON.stringify([1, undefined, () => {}]));
// [1,null,null]

这就是接口数据里数组长度能保留,但对象字段可能消失的原因。

三、数字和 BigInt 的边界

JSON 数字不支持 NaNInfinity-Infinity,它们会变成 null

JSON.stringify({ a: NaN, b: Infinity }); // {"a":null,"b":null}

BigInt 默认不能被 JSON 序列化。

JSON.stringify({ id: 1n }); // TypeError

如果后端 ID 可能超过安全整数,比如 9007199254740993,前端最好用字符串承接,避免精度丢失。

四、toJSON、replacer 和 space

对象可以定义 toJSON 控制序列化结果。

const user = {
  name: "Ada",
  password: "secret",
  toJSON() {
    return { name: this.name };
  }
};

JSON.stringify(user); // {"name":"Ada"}

replacer 可以过滤或转换字段,space 用于格式化输出。

JSON.stringify({ a: 1, b: 2 }, ["a"], 2);
// {
//   "a": 1
// }

五、parse 的 reviver 可以做恢复

JSON.parse 的第二个参数 reviver 会自底向上处理解析结果。

const result = JSON.parse('{"date":"2026-07-29"}', (key, value) => {
  if (key === "date") return new Date(value);
  return value;
});

这常用于把日期字符串恢复成 Date,或者对危险字段做过滤。

六、循环引用和深拷贝限制

JSON 方案不能处理循环引用,也会丢掉原型、方法、undefinedMapSet 等信息。

object
  ├─ name: "node"
  └─ self ──┐
       ▲    │
       └────┘

这种结构序列化会抛 TypeError。如果要处理复杂对象,应考虑 structuredClone 或专门的序列化方案。

七、常见误区与追问

  • 误区:JSON.stringify 可以安全深拷贝任何对象。 它会丢失函数、原型、特殊对象和循环引用。
  • 误区:对象里的 undefined 会变成 null。 对象属性会被忽略,数组元素才会变成 null
  • 误区:Date 解析回来还是 Date。 默认回来是字符串,需要 reviver 恢复。
  • 误区:BigInt 会自动转成数字。 默认会抛错,不能直接序列化。
  • 追问:replacer 和 reviver 分别在什么时候执行? replacer 在 stringify 阶段过滤转换,reviver 在 parse 阶段恢复转换。
  • 追问:接口大整数为什么常用字符串? 因为 JavaScript Number 有安全整数上限,超过后可能丢精度。

八、加强记忆

记忆路径:

JS value -> stringify -> JSON text -> parse -> JS value

中间这段 JSON text 只承载 JSON 类型。答题时抓三个点:对象和数组对特殊值处理不同;循环引用和 BigInt 会抛错;replacerrevivertoJSON 可以定制转换。这样既能讲 API,也能讲限制。