第 20 章 JSON

87 阅读3分钟

JSON 是 JavaScript 的一个严格的子集,利用了 JavaScript中的一些模式来表示结构化数据。JSON,最重要的是要理解它是一种数据格式,不是一种编程语言。JSON 并不从属于 JavaScript,很多编程语言都有针对 JSON 的解析器和序列化器。

20.1 语法

JSON 的语法可以表示以下三种类型的值。

  • 简单值:使用与 JavaScript 相同的语法,可以在 JSON 中表示字符串、数值、布尔值和 null。 但 JSON 不支持 JavaScript 中的特殊值 undefined
  • 对象:对象作为一种复杂数据类型,表示的是一组无序的键值对儿。而每个键值对儿中的值可 以是简单值,也可以是复杂数据类型的值。
  • 数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中 的值。数组的值也可以是任意类型——简单值、对象或数组。

JSON 不支持变量、函数或对象实例

JavaScript 字符串与 JSON 字符串的最大区别在于,JSON 字符串必须使用双引号

20.2 解析与序列化

JSON 之所以流行,可以把JSON 数据结构解析为有用的 JavaScript 对象。

20.2.1 JSON对象

早期的 JSON 解析器基本上就是使用 JavaScript 的 eval()函数。eval()函数可以解析、解释并返回 JavaScript 对象和数组。

ECMAScript 5 对解析 JSON 的行为进行规范,定义了全局对象 JSON。JSON 对象有两个方法:stringify()和 parse()。

20.2.2 序列化选项

JSON.stringify()除了要序列化的 JavaScript 对象外,还可以接收另外两个参数。

JSON.stringify(value[, replacer [, space]])
  • replacer,表示过滤器。可以是数组,也可以是个函数。
  • space,表示是否在 JSON 字符串中保留缩进

使用数组过滤结果

var book = {
    "title": "Professional JavaScript",
    "authors": [
        "Nicholas C. Zakas"
    ],
    edition: 3,
    year: 2011
};

var jsonText = JSON.stringify(book, ["title", "edition"]);

以上例子中第二个参数是个数组,包含两个字符串:"title"和"edition"。这两个属性与将要序列化的对象中的属性是对应的,因此在返回的结果中,就只会包含这两个属性。

{"title":"Professional JavaScript","edition":3}

使用函数过滤结果

var book = {
    "title": "Professional JavaScript",
    "authors": [
        "Nicholas C. Zakas"
    ],
    edition: 3,
    yer: 2011
};

var jsonText = JSON.stringify(book, function(key, value){
    switch(key){
        case "authors":
            return value.join(",")
        case "year":
            return 5000;
        case "edition":
            return undefined;
        default:
            return value;
    }
});

序列化后的 JSON 字符串如下所示:

{"title":"Professional JavaScript","authors":"Nicholas C. Zakas","year":5000}

字符串缩进

var book = {
    "title": "Professional JavaScript",
    "authors": [
        "Nicholas C. Zakas"
    ],
    edition: 3,
    year: 2011
};
var jsonText = JSON.stringify(book, null, 4);

最终保存在 jsonText 中的字符串如下所示:

{
    "title": "Professional JavaScript",
    "authors": [
        "Nicholas C. Zakas"
    ],
    "edition": 3,
    "year": 2011
}

toJSON()方法

有时候,JSON.stringify()还是不能满足对某些对象进行自定义序列化的需求。在这些情况下, 可以给对象定义 toJSON()方法,返回其自身的 JSON 数据格式。

toJSON()可以作为函数过滤器的补充,因此理解序列化的内部顺序十分重要。假设把一个对象传 入 JSON.stringify(),序列化该对象的顺序如下。

  • 如果存在 toJSON()方法而且能通过它取得有效的值,则调用该方法。否则,返回对象本身。
  • 如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第(1)步返回的值。
  • 对第(2)步返回的每个值进行相应的序列化。
  • 如果提供了第三个参数,执行相应的格式化。

20.2.3 解析选项

JSON.parse()方法也可以接收另一个参数,该参数是一个函数,这个函数被称为还原函数(reviver)。

var book = {
    "title": "Professional JavaScript",
    "authors": [
        "Nicholas C. Zakas"
    ],
    edition: 3,
    year: 2011,
    releaseDate: new Date(2011, 11, 1)
};
var jsonText = JSON.stringify(book);

var bookCopy = JSON.parse(jsonText, function(key, value){
    if (key == "releaseDate"){
        return new Date(value);
    } else {
        return value;
    }
});
alert(bookCopy.releaseDate.getFullYear());

还原函数在遇到"releaseDate"键时,会基于相应的值创建一个新的 Date 对象。结果就是 bookCopy.releaseDate 属性中会保存一个 Date 对象。