讲解
JSON(JavaScript Object Notation)是源自 JavaScript 对象语法的文本数据格式,如今是所有语言通用的数据交换标准:接口返回、配置文件、本地存储几乎都是 JSON。它和对象字面量长得像,但规则更严格:键必须双引号、字符串必须双引号、不允许尾逗号、只允许字符串/数字/布尔/null/数组/对象六种值——undefined、函数、Symbol、Date 都不是合法 JSON。
JavaScript 用两个方法做转换:JSON.stringify(value) 把值序列化成 JSON 字符串,JSON.parse(text) 把 JSON 字符串解析回值。stringify 的二三参数很实用:第二个参数是替换函数或属性白名单数组,第三个参数是缩进空格数(调试打印神器 JSON.stringify(obj, null, 2))。parse 的第二个参数是 reviver 函数,可以逐个键值对做转换(比如把日期字符串转回 Date)。
序列化有几个必须知道的「静默行为」:undefined、函数、Symbol 值会被丢弃(数组里则变 null);Date 变成 ISO 字符串(解析回来不会自动变回 Date);NaN 和 Infinity 变 null;循环引用直接抛 TypeError。JSON.parse(JSON.stringify(obj)) 曾被当作深拷贝捷径,正因为上述丢失行为,现在请用 structuredClone。
示例
const user = {
name: '小明',
age: 18,
password: 'secret',
greet() {
return 'hi';
},
nickname: undefined,
};
// 序列化:函数和 undefined 被丢弃
const text = JSON.stringify(user);
console.log('序列化:', text);
// 美化输出
console.log(JSON.stringify(user, null, 2));
// 白名单:只保留指定字段
console.log('白名单:', JSON.stringify(user, ['name', 'age']));
// 解析
const parsed = JSON.parse(text);
console.log('解析回来:', parsed.name, ',方法没了:', parsed.greet);
// reviver:把日期字符串转回 Date
const record = JSON.parse('{"day":"2026-08-09T00:00:00.000Z"}', (key, value) => {
if (key === 'day') return new Date(value);
return value;
});
console.log('reviver 后是 Date:', record.day instanceof Date);
// 循环引用抛错
const loop = { name: 'loop' };
loop.self = loop;
try {
JSON.stringify(loop);
} catch (e) {
console.log('循环引用:', e.constructor.name);
}
// 解析坏 JSON 抛错,记得 try/catch
try {
JSON.parse('{bad json}');
} catch (e) {
console.log('解析失败:', e.constructor.name);
}
常见坑
- 以为序列化是无损往返:函数、undefined、Symbol 丢失,Date 变字符串,NaN 变 null——parse(stringify(x)) 和 x 经常不等价。
- JSON 里写单引号或尾逗号:从配置文件抄过来的 'key': 或结尾逗号会让 parse 报错。JSON 比 JS 对象字面量严格。
- 不包 try/catch 解析外部数据:接口、localStorage 里的数据可能被损坏或手工改过,裸 JSON.parse 是线上崩溃的常见来源。
- 用 JSON 做深拷贝丢数据后排查半天:日期变了、undefined 没了,bug 隐蔽。深拷贝用 structuredClone。
小结
stringify 序列化、parse 反序列化,各带一个定制函数参数;记住丢失清单(函数/undefined/Symbol/Date/NaN)。下一节学习错误处理。