返回首页 返回笔记列表

JSON.parse() 与 JSON.stringify() 的使用场景与陷阱

作者:本站站长
发布日期:2025年9月26日

在现代 Web 开发中,JSON.parse()JSON.stringify() 是处理数据序列化和反序列化的两个核心方法。它们看似简单,但若不了解其细节,极易掉入“陷阱”。

一、基本介绍

// 示例:基础用法
const obj = { name: "张三", age: 25 };
const jsonStr = JSON.stringify(obj);
console.log(jsonStr); // '{"name":"张三","age":25}'

const parsedObj = JSON.parse(jsonStr);
console.log(parsedObj.name); // "张三"

二、常见使用场景

1. 存储数据到 localStorage

localStorage 只能存储字符串,因此需要先用 stringify 转换对象。

// 保存用户信息
const user = { id: 1, username: "alice" };
localStorage.setItem("user", JSON.stringify(user));

// 读取用户信息
const savedUser = JSON.parse(localStorage.getItem("user"));
console.log(savedUser.username); // "alice"

2. 发送数据给服务器(API 请求)

发送 POST 请求时,通常需要将数据转为 JSON 字符串。

fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: "李四", email: "lisi@example.com" })
});

3. 接收服务器返回的 JSON 数据

从 API 获取的数据是字符串,需用 parse 转为对象使用。

fetch('/api/data')
  .then(res => res.text()) // 或直接 .json()
  .then(text => {
    const data = JSON.parse(text);
    console.log(data);
  });

4. 深拷贝对象(有限制)

利用 stringify + parse 实现浅层深拷贝(见下文陷阱)。

const original = { a: 1, b: { c: 2 } };
const copy = JSON.parse(JSON.stringify(original));
copy.b.c = 999;
console.log(original.b.c); // 2 → 原对象未被修改

三、常见陷阱与解决方案

⚠️ 警告:以下陷阱在实际开发中非常容易引发 bug!

1. 函数、undefined、Symbol 会被忽略

JSON.stringify() 会自动忽略这些值。

const obj = {
  name: "测试",
  fn: function() {},        // ❌ 被忽略
  value: undefined,         // ❌ 被忽略
  sym: Symbol("id")         // ❌ 被忽略
};

console.log(JSON.stringify(obj));
// 输出:{"name":"测试"} → 其他字段丢失!
💡 提示:如需序列化函数,应使用其他方案(如模板、代码生成),或提前转换。

2. 循环引用导致错误

对象内部存在循环引用时,stringify 会抛出错误。

const obj = { name: "循环" };
obj.self = obj; // 自引用

JSON.stringify(obj); 
// ❌ 报错:TypeError: Converting circular structure to JSON
💡 解决方案:使用第三方库如 circular-json,或手动清理引用。

3. Date 对象被转为字符串

stringify 会将 Date 转为 ISO 字符串,parse 不会自动还原为 Date。

const obj = { date: new Date() };
const str = JSON.stringify(obj);
console.log(str); // {"date":"2025-09-26T02:39:00.000Z"}

const parsed = JSON.parse(str);
console.log(parsed.date); // "2025-09-26T02:39:00.000Z" → 字符串,不是 Date!
💡 解决方案:使用 parse 的第二个参数(reviver)手动还原:
const parsed = JSON.parse(str, (key, value) => {
  if (key === 'date') return new Date(value);
  return value;
});

4. BigInt 类型不支持

const obj = { id: 123n };
JSON.stringify(obj); 
// ❌ 报错:TypeError: Do not know how to serialize a BigInt
💡 解决方案:手动转为字符串:
JSON.stringify(obj, (key, value) => 
  typeof value === 'bigint' ? value.toString() : value
);

5. 精度丢失(大数字)

JavaScript 数字精度限制可能导致超大整数出错。

const obj = { id: 9007199254740993 }; // 超过 Number.MAX_SAFE_INTEGER
console.log(JSON.parse(JSON.stringify(obj)).id); 
// 可能输出 9007199254740992 → 精度丢失!
💡 建议:ID 类大数建议以字符串形式传输。

四、高级技巧:replacer 与 reviver

1. replacer(过滤/转换输出)

const user = { name: "Alice", password: "123", token: "abc" };

// 过滤敏感字段
const safeStr = JSON.stringify(user, ['name']); 
// 只保留 name 字段

// 或使用函数动态处理
const masked = JSON.stringify(user, (key, value) => {
  if (key === 'password') return '[REDACTED]';
  return value;
});
console.log(masked); // {"name":"Alice","password":"[REDACTED]","token":"abc"}

2. reviver(解析时处理数据)

const str = '{"birth":"1990-01-01"}';
const data = JSON.parse(str, (key, value) => {
  if (key === 'birth') return new Date(value);
  return value;
});
console.log(data.birth.getFullYear()); // 1990 → 已是 Date 对象

五、总结

方法 用途 注意事项
JSON.stringify() 对象 → JSON 字符串 忽略函数/undefined/Symbol;不能处理循环引用;Date 变字符串
JSON.parse() JSON 字符串 → 对象 不会还原 Date;需注意 XSS 风险(仅解析可信数据)
最佳实践:

掌握 JSON.parse()JSON.stringify() 的正确用法,能让你在前后端交互、状态管理、数据持久化等场景中游刃有余。避开陷阱,写出更健壮的代码!