本章内容
理解 JSON 语法
解析 JSON
JSON 序列化
1 语法
JSON 语法支持表示 3 种类型的值。
简单值:字符串、数值、布尔值和 null 可以在 JSON 中出现,就像在 JavaScript 中一样。特殊值 undefined 不可以。
对象:第一种复杂数据类型,对象表示有序键/值对。每个值可以是简单值,也可以是复杂类型。
数组:第二种复杂数据类型,数组表示可以通过数值索引访问的值的有序列表。数组的值可以是任意类型,包括简单值、对象,甚至其他数组。
1.1 简单值
5
"Hello world!"
JavaScript 字符串与 JSON 字符串的主要区别是,JSON 字符串必须使用双引号(单引号会导致语法错误)。
1.2 对象
"name": "Nicholas",
"age": 29
}
1.3 数组
[25, "hi", true]
2 解析与序列化
2.1 JSON 对象
JSON 对象有两个方法:stringify()和 parse()。在简单的情况下,这两个方法分别可以将JavaScript 序列化为 JSON 字符串,以及将 JSON 解析为原生 JavaScript 值。例如:
let book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas",
"Matt Frisbie"
],
edition: 4,
year: 2017
};
let jsonText = JSON.stringify(book);
// {"title":"Professional JavaScript","authors":["Nicholas C. Zakas","Matt Frisbie"], "edition":4,"year":2017}
在序列化 JavaScript 对象时,所有函数和原型成员都会有意地在结果中省略。此外,值为 undefined的任何属性也会被跳过。
JSON 字符串可以直接传给 JSON.parse(),然后得到相应的 JavaScript 值。
let bookCopy = JSON.parse(jsonText);
2.2 序列化选项
JSON.stringify()方法除了要序列化的对象,还可以接收两个参数。第一个参数是过滤器(可以是数组或函数);第二个参数是用于缩进结果 JSON 字符串的选项。单独或组合使用这些参数可以更好地控制 JSON 序列化。
1. 过滤结果
如果第二个参数是一个数组,那么 JSON.stringify()返回的结果只会包含该数组中列出的对象属性。比如下面的例子:
let book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas",
"Matt Frisbie"
],
edition: 4,
year: 2017
};
let jsonText = JSON.stringify(book, ["title", "edition"]);
// {"title":"Professional JavaScript","edition":4}
如果第二个参数是一个函数,提供的函数接收两个参数:属性名(key)和属性值(value)。可以根据这个 key 决定要对相应属性执行什么操作。这个 key 始终是字符串,只是在值不属于某个键/值对时会是空字符串。
let book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas",
"Matt Frisbie"
],
edition: 4,
year: 2017
};
let jsonText = JSON.stringify(book, (key, value) => {
switch(key) {
case "authors":
return value.join(",")
case "year":
return 5000;
case "edition":
return undefined;
default:
return value;
}
});
// {"title":"Professional JavaScript","authors":"Nicholas C. Zakas,Matt Frisbie","year":5000}
2. 字符串缩进
JSON.stringify()方法的第三个参数控制缩进和空格。在这个参数是数值时,表示每一级缩进的空格数。例如,每级缩进 4 个空格,可以这样:
let book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas",
"Matt Frisbie"
],
edition: 4,
year: 2017
};
let jsonText = JSON.stringify(book, null, 4);
//jsonText 结果
{
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas",
"Matt Frisbie"
],
"edition": 4,
"year": 2017
}
注意,除了缩进,JSON.stringify()方法还为方便阅读插入了换行符。这个行为对于所有有效的缩进参数都会发生。(只缩进不换行也没什么用。)最大缩进值为 10,大于 10 的值会自动设置为 10。
如果缩进参数是一个字符串而非数值,那么 JSON 字符串中就会使用这个字符串而不是空格来缩进。使用字符串,也可以将缩进字符设置为 Tab 或任意字符,如两个连字符:
let jsonText = JSON.stringify(book, null, "--" );
//jsonText
{
--"title": "Professional JavaScript",
--"authors": [
----"Nicholas C. Zakas",
----"Matt Frisbie"
--],
--"edition": 4,
--"year": 2017
}
3. toJSON()方法
有时候,对象需要在 JSON.stringify()之上自定义 JSON 序列化。此时,可以在要序列化的对象中添加 toJSON()方法,序列化时会基于这个方法返回适当的 JSON 表示。
下面的对象为自定义序列化而添加了一个 toJSON()方法:
let book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas",
"Matt Frisbie"
],
edition: 4,
year: 2017,
toJSON: function() {
return this.title;
}
};
let jsonText = JSON.stringify(book);
2.3 解析选项
JSON.parse()方法也可以接收一个额外的参数,这个函数会针对每个键/值对都调用一次。这个函数被称为还原函数(reviver)。
let book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas",
"Matt Frisbie"
],
edition: 4,
year: 2017,
releaseDate: new Date(2017, 11, 1)
};
let jsonText = JSON.stringify(book);
let bookCopy = JSON.parse(jsonText,
(key, value) => key == "releaseDate" ? new Date(value) : value);
alert(bookCopy.releaseDate.getFullYear());
3 小结
JSON 是一种轻量级数据格式,可以方便地表示复杂数据结构。这个格式使用 JavaScript 语法的一个子集表示对象、数组、字符串、数值、布尔值和 null。虽然 XML 也能胜任同样的角色,但 JSON 更简洁,JavaScript 支持也更好。更重要的是,所有浏览器都已经原生支持全局 JSON 对象。