0%

JavaScript学习笔记(20)

《JavaScript高级程序设计》第二十章,JSON。


省略了18章(JavaScript与XML)和19章(E4X),这两章都是关于XML,API还挺多的,不过感觉现在很多都换成了JSON,就先跳过XML了。

JSON是JavaScript Object Notation,下面就简单记录下它。

语法

JSON可以表示三种类型的值:简单值、对象、数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 简单值举例
5
"Hello world"

// 对象举例
{
"name": "Nicholas",
"age": 29
}

// 数组举例
[25, "hi", true]
[
{
"title": "abook",
"authors": [
"Nicholas"
]
},
{
"title": "bbook",
"authors": [
"Glen"
]
}
]

这里唯一要注意的就是,属性名或字符串必须用双引号。

早期的JSON解析器基本是使用JavaScript的eval()函数,因为JSON是JavaScript语法的子集,所以eval()可以解析、解释并返回JavaScript对象和数组。后面ECMAScript5进行了规范,定义了全局对象JSON,它有序列化方法和解析方法。

序列化

JSON.stringify()将JavaScript对象序列化为JSON字符串。默认结果不含任何空格和缩进。

1
2
3
4
5
6
7
8
9
10
11
const book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011
};

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

个性化的JSON.stringify()可以接收2个额外的参数:

  • 筛选字段的过滤器
    可以是筛选属性名的数组,也可以是参数为keyvalue的自定义函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /* 
    传入数组

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

    */
    const jsonText1 = JSON.stringify(book, ["title", "edition"]);

    /*
    传入函数

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

    */
    const jsonText2 = JSON.stringify(book, function(key, value) {
    switch(key) {
    case "authors":
    return value.join(",");
    case "year":
    return 5000;
    case "edition":
    return undefined; // 值为undefined的属性不会被序列化
    default:
    return value;
    }
    });
  • 表示是否保留缩进的选项
    可以是表示缩进空格数的数字,也可以是用作缩进的字符串。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // 缩进选项

    /*
    传入数字

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

    */
    const jsonText1 = JSON.stringify(book, null, 4);

    /*
    传入字符串

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

    */
    const jsonText2 = JSON.stringify(book, null, "--");

有时候JSON.stringify()还是不能满足需求,这种时候可以通过对象上调用toJSON()方法来返回自定义的JSON数据格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011,

toJSON: function() {
return this.title;
}

};

const jsonText = JSON.stringify(book);
// "Professional JavaScript"

* 序列化顺序

  1. 如果存在toJSON()且能通过它取得有效的值,则调用该方法。否则按照默认顺序执行序列化。
  2. 如果提供了第二个参数,则使用过滤器,传入过滤器的值是(1)返回的值。
  3. 对(2)返回的每个值进行序列化。
  4. 如果提供了第三个参数,执行相应的格式化。

解析

JSON.parse()将JSON字符串解析成JavaScript对象。

1
2
3
4
5
6
7
const book = ...;

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

const bookCopy = JSON.parse(jsonText);
// bookCopy和book是两个独立的、没有任何关系的对象

当然,JSON.parse()也可以接收一个函数作为参数,与过滤函数(replacer)对应,叫做还原函数(reviver)。这个函数也是接收keyvalue作为参数,通常用于把一些序列化了的内容还原成相应对象,譬如将日期字符串转换为Date对象等,举例如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011,

releaseDate: new Date(2011, 11, 1);

};

const jsonText = JSON.stringify(book);

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

// 使用还原函数后,这里parse出来的releaseDate就是Date对象了,才能用getFullYear()
alert(bookCopy.releaseDate.getFullYear());