JSON.parse() 可能抛出 SyntaxError,主因是输入非标准JSON字符串,如单引号、尾逗号、undefined/NaN、未引键名等;需 trim() 去BOM/空格,用 safeParse 封装容错。

JSON.parse() 会抛出 SyntaxError?先检查字符串是否合法
绝大多数 SyntaxError: Unexpected token 都是因为传给 JSON.parse() 的不是标准 JSON 字符串。常见陷阱包括:单引号代替双引号、末尾多逗号、使用 undefined / NaN / 注释、键名没加引号。
-
后端返回的
response.text()可能含 BOM 或空白字符,建议先trim() -
浏览器控制台复制的对象(如
{a: 1})不是 JSON,需手动转成{"a": 1} - 服务端用
JSON.stringify()生成时若未处理循环引用,前端解析会失败 —— 这问题不在解析侧,而在生成侧
const raw = '{"name": "Alice", "age": 30}';
const data = JSON.parse(raw); // ✅ 正确
const bad = "{'name': 'Alice'}"; // ❌ 单引号
const bad2 = '{"name": "Alice",}'; // ❌ 末尾逗号(JSON 不允许)
// 安全解析封装示例
function safeParse(jsonStr) {
try {
return JSON.parse(jsonStr.trim());
} catch (e) {
console.error('JSON parse failed:', e.message);
return null;
}
}
JSON.stringify() 处理 Date / Set / Map / 循环引用
JSON.stringify() 默认忽略函数、undefined、Symbol,且对 Date、Set、Map 和循环引用直接失效 —— 不报错但结果不符合预期。
-
Date对象会被转成 ISO 字符串(✅ 可接受),但若需自定义格式,必须用replacer函数 -
Set和Map默认序列化为空对象{},需手动展开为数组 - 循环引用会直接抛
TypeError: Converting circular structure to JSON
const obj = { now: new Date(), tags: new Set(['js', 'json']) };
obj.self = obj; // 循环引用
// ✅ 手动处理 Set/Map + 防循环
function jsonSafeStringify(value) {
const seen = new WeakMap();
return JSON.stringify(value, (key, val) => {
if (val instanceof Set) return Array.from(val);
if (val instanceof Map) return Object.fromEntries(val);
if (typeof val === 'object' && val !== null) {
if (seen.has(val)) return '[Circular]';
seen.set(val, true);
}
return val;
});
}
嵌套结构深拷贝不能只靠 JSON.parse(JSON.stringify())
这个“快捷深拷贝”写法在很多场景下看似有效,但有严重限制:丢失原型链、函数、Date(虽转成字符串但不再是 Date 实例)、RegExp、undefined、NaN、BigInt、循环引用直接崩溃。
- 仅适用于纯数据对象(POJO),且不含上述特殊类型
- 性能上比
structuredClone()差,尤其大数据量时多一次序列化/反序列化开销 - IE 和旧版 Safari 不支持
structuredClone(),可用lodash.cloneDeep()替代
// ❌ 错误假设:能拷贝一切
const original = { fn: () => {}, date: new Date() };
const copy = JSON.parse(JSON.stringify(original)); // copy.fn === undefined, copy.date === "2024-05-..."(字符串)
// ✅ 现代浏览器推荐
const copy = structuredClone(original);
// ✅ 兼容性方案(需引入 lodash)
import { cloneDeep } from 'lodash-es';
const copy = cloneDeep(original);
处理带类型信息的 JSON(如后端返回的 class 实例模拟)
JSON 本身无类型,但业务中常需把 JSON 还原为带方法的类实例(例如 User 类)。不能依赖 JSON.parse() 自动构造,必须手动映射。
立即学习“Java免费学习笔记(深入)”;
- 避免在
replacer中做复杂逻辑,应在解析后统一转换 - 若字段名与类属性不一致(如 API 返回
user_name,类用name),需在转换函数里做映射 - 多个嵌套层级(如
user.posts[0].author)需递归处理,或用库如class-transformer(TS 环境)
class User {
constructor(data) {
this.id = data.id;
this.name = data.user_name || data.name;
this.createdAt = data.created_at ? new Date(data.created_at) : null;
}
fullName() { return this.name; }
}
// 解析后手动实例化
const rawData = '{"id": 1, "user_name": "Bob", "created_at": "2024-05-01T10:00:00Z"}';
const parsed = JSON.parse(rawData);
const user = new User(parsed); // ✅ 得到带方法的实例
实际项目中,JSON 的边界最常模糊在「谁负责校验结构」——前端不该假设后端返回永远合法,也不该在每一层都写 ?.name ?? 'N/A'。真正省事的做法是:用 TypeScript 定义接口 + 运行时 schema 校验(如 zod 或 ajv),把错误拦截在解析后、使用前。











