简介
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用来序列化对象、数组、数值、字符串、布尔值和 null。
JSON 语法规则
- 字符串必须使用双引号,不能用单引号
- 对象的键名必须是双引号字符串
- 不支持注释,最后一个属性后不能有逗号
- 数值不能有前导零,不能是 NaN 或 Infinity
// 合法 JSON
{ "name": "Tom", "age": 20 }
// 非法 JSON
{ name: "Tom" } // 键名没有双引号
{ "name": 'Tom' } // 值用了单引号
{ "name": "Tom", } // 末尾逗号
JSON 只支持字符串、数值、布尔、null、对象和数组这几种值类型,不支持 JavaScript 中的函数、undefined、Symbol、Date 等。
JSON.stringify()
将一个 JavaScript 值转换为 JSON 字符串。
JSON.stringify(value[, replacer[, space]])
基本转换规则:
- undefined、函数、Symbol 在对象属性中被忽略,在数组中转为 null
- NaN 和 Infinity 转为 null
- Date 对象转为 ISO 字符串
- 不可枚举属性被忽略
JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify({x: undefined, y: Object, z: Symbol("")});
// '{}'
JSON.stringify([undefined, Object, Symbol("")]);
// '[null,null,null]'
JSON.stringify(NaN); // 'null'
JSON.stringify(new Date()); // '"2018-01-11T00:00:00.000Z"'
replacer 参数
replacer 为函数时,每个属性都经过该函数处理;为数组时,只序列化指定的属性名。
function replacer(key, value) {
if (typeof value === "string") {
return undefined;
}
return value;
}
var foo = { foundation: "Mozilla", model: "box", week: 45, month: 7 };
JSON.stringify(foo, replacer);
// '{"week":45,"month":7}'
JSON.stringify(foo, ['week', 'month']);
// '{"week":45,"month":7}'
space 参数
用于美化输出,可以是数字(缩进空格数)或字符串。
var obj = { a: 1, b: { c: 2 } };
JSON.stringify(obj, null, 2);
// '{
// "a": 1,
// "b": {
// "c": 2
// }
// }'
toJSON 方法
如果对象定义了 toJSON 方法,序列化时会调用该方法的返回值。
var obj = {
foo: 'foo',
toJSON: function () { return 'bar'; }
};
JSON.stringify(obj); // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'
JSON.parse()
将 JSON 字符串解析为 JavaScript 值。
JSON.parse(text[, reviver])
reviver 参数
reviver 函数用于在返回之前对解析的值进行转换。遍历顺序从内到外,最后处理顶层对象(key 为空字符串)。
JSON.parse('{"p": 5}', function (k, v) {
if (k === '') return v;
return v * 2;
});
// { p: 10 }
// 日期字符串还原为 Date 对象
var str = '{"date":"2018-01-11T00:00:00.000Z","name":"test"}';
JSON.parse(str, function (key, value) {
if (key === 'date') return new Date(value);
return value;
});
深拷贝应用
利用 JSON 序列化和反序列化实现深拷贝:
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
var original = { a: 1, b: { c: 2 }, d: [1, 2, 3] };
var copy = deepClone(original);
copy.b.c = 99;
original.b.c; // 2,不受影响
局限性——以下类型无法正确处理:
var obj = {
fn: function() {}, // 函数丢失
undef: undefined, // undefined 丢失
date: new Date(), // Date 变成字符串
reg: /hello/g, // 正则变成空对象 {}
nan: NaN, // NaN 变成 null
inf: Infinity // Infinity 变成 null
};
JSON.parse(JSON.stringify(obj));
// { date: "2018-01-11T...", reg: {}, nan: null, inf: null }
常见陷阱
循环引用
var a = {};
a.self = a;
JSON.stringify(a); // TypeError: Converting circular structure to JSON
特殊值
JSON.stringify(BigInt(1)); // TypeError
JSON.stringify(new Map([['a', 1]])); // '{}'
JSON.stringify(new Set([1, 2, 3])); // '{}'
parse 对格式严格
JSON.parse("'hello'"); // SyntaxError,必须双引号
JSON.parse("{a: 1}"); // SyntaxError,键名必须双引号
JSON.parse("undefined"); // SyntaxError,undefined 不是合法 JSON