JSON详解

1,791 阅读7分钟

这是我参与更文挑战的第18天,活动详情查看: 更文挑战

介绍

JSON: JavaScript Object Notation(JavaScript 对象表示法)

JSON 是存储和交换文本信息的语法,类似 XML。

JSON 比 XML 更小、更快,更易解析。

实例

{
    "message": [
    { "name":"Jack" , "address":"A" }, 
    { "name":"Mary" , "address":"B" }, 
    { "name":"Tom" , "address":"C" }
    ]
}
  • 关于 JSON,最重要的是要理解它是一种数据格式,不是一种编程语言。虽然具有相同的语法形式,但 JSON 并不从属于 JavaScript。而且,并不是只有 JavaScript 才使用 JSON,毕竟 JSON 只是一种数据格式。很多编程语言都有针对 JSON 的解析器和序列化器。

  • JSON 是一个轻量级的数据格式,可以简化表示复杂数据结构的工作量。JSON 使用 JavaScript 语法的子集表示对象、数组、字符串、数值、布尔值和 null **。

  • 即使 XML 也能表示同样复杂的数据结果,但JSON 没有那么烦琐,而且在 JavaScript 中使用更便利。ECMAScript 5 定义了一个原生的 JSON 对象; JSON对象包含两个方法: 用于解析 JavaScript Object Notation (JSON) 的 parse() 方法,以及将对象/值转换为 JSON字符串的 stringify() 方法。

JSON语法

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

  • 简单值:使用与 JavaScript 相同的语法,可以在 JSON 中表示字符串、数值、布尔值和 null 。但 JSON 不支持 JavaScript 中的特殊值 undefined 。

  • 对象:对象作为一种复杂数据类型,表示的是一组无序的键值对儿。而每个键值对儿中的值可以是简单值,也可以是复杂数据类型的值。

  • 数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型 —— 简单值对象数组JavaScript 与 JSON 的区别

JavaScript类型JSON 的不同点
对象和数组属性名称必须是双引号括起来的字符串;最后一个属性后不能有逗号。
数值禁止出现前导零( JSON.stringify 方法自动忽略前导零,而在 JSON.parse 方法中将会抛出 SyntaxError);如果有小数点, 则后面至少跟着一位数字。
字符串只有有限的一些字符可能会被转义;禁止某些控制字符; Unicode 行分隔符 (U+2028)和段分隔符 (U+2029)被允许 ; 字符串必须用双引号括起来。请参考下面的示例,可以看到 JSON.parse() 能够正常解析,但将其当作JavaScript解析时会抛出 SyntaxError 错误:
示例
let code = '"\u2028\u2029"';
JSON.parse(code);  // 正常
eval(code);  // 错误

语法

JSON 语法是 JavaScript 对象表示语法的子集。

  • 数据在名称/值对中

  • 数据由逗号分隔

  • 大括号 {} 保存对象

  • 中括号 [] 保存数组,数组可以包含多个对象

书写格式

key : value

简单值

注意 字符串必须使用双引号("")

最简单的 JSON 数据形式就是简单值;

包括:字符串数值(必须是十进制标识)、布尔值Null

// 字符串
{ "msg": "Hello JSON" }
// 数字(整数或浮点数)
{ "age": "18" }
// 布尔值
{ "flag": true }
// null
{ "money": null }

JSON 更多的是用来表示复杂的数据结构,简单值只是整个数据结构中的一部分。

对象

对象语法

{ "msg": "Hello JSON", "age": "18" }

访问对象值

  1. 使用点号(.)
let Obj, x;
Obj = { "msg": "Hello JSON", "age": "18" };
x = Obj.name;  // Hello JSON
  1. 使用中括号([])
let Obj, x;
Obj = { "msg": "Hello JSON", "age": "18" };
x = Obj["name"];  // Hello JSON

嵌套

JSON 对象在大括号 {} 中书写,对象可以包含多个名称/值对;

即JSON 对象中可以包含另外一个 JSON 对象 示例

{
    "name": "Mary",
    "age": 18
    "address": {
	"name":"地址名"
        "city": "广州市",
        "location": "xx路XX号"  
    }
}

这里虽然出现两个 "name" 属性,但由于它们分别属于不同的对象,因此这样完全没有问题。不过,同一个对象中绝对不应该出现两个同名属性。

数组

注意 JSON 数组在中括号 [] 中书写

JSON 对象中的数组 对象属性的值可以是一个数组

{
"name": "Jack",
"age": 18,
"hobby": [ "eat", "sport", "drink" ]
}

访问数组值

使用索引值

let x = Obj.hobby[0]  // eat

嵌套

JSON 对象中数组可以包含另外一个数组,或者另外一个 JSON 对象

myObj = {
    "name": "Jack",
    "age": 18,
    "hobby": [
        { "name":"eat", "info":[ "米饭", "水果", "美食" ] },
        { "name":"sport", "info":[ "跑步", "游泳", "跳高" ] },
        { "name":"drink", "info":[ "果汁", "可乐" ] }
    ]
}

解析和序列化

JSON 对象有两个方法: stringify()parse() 。在最简单的情况下,这两个方法分别用于把JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值。

JSON.stringify()

用法 JSON对象转为JSON字符串(在向服务器发送数据时一般是字符串)

假如我们向服务器发送以下数据

let JSONObj = {
    title: "JSON",
    authors: [
        "Jack"
    ],
    age: 18,
};
let JSONStr = JSON.stringify(JSONObj);
console.log(JSONStr);  // {"title":"JSON","authors":["Jack"],"age":18}
console.log(typeof JSONObj);  // object
console.log(typeof JSONStr);  // string

默认情况下, JSON.stringify() 输出的 JSON 字符串不会存在空格字符缩进

异常

1. 解析数据

  • JSON 不能存储 Date 对象。

  • JSON.stringify() 会将所有日期转换为字符串。

var obj = { "name":"Jack", "initDate":new Date()};
var myJSON = JSON.stringify(obj); // {"name":"Jack","initDate":"2021-06-07T02:44:33.788Z"}

之后你可以再将字符串转换为 Date 对象。

2. 解析函数

JSON 不允许包含函数,JSON.stringify() 会删除 JavaScript 对象的函数,包括 key 和 value。除此之外undefined也会被删除

let JSONObj = {
    age: 18,
    test1: undefined,
    test2: function(){return 1+1}
};
let JSONStr = JSON.stringify(JSONObj);
console.log(JSONStr);  // {"age":18}

在序列化 js 对象时,所有函数原型成员都会被有意忽略,不体现在结果中。此外,值为 undefined 的任何属性也都会被跳过。结果都是值为有效 JSON 数据类型的实例属性。

上面的 test1test2 将不会出现最终的结果中

接下来我们再看看另外两个参数(可选参数) snipaste20210607_111630.png 简单来说

  • replacer 可以充当一个过滤器的作用
  • space 字符串缩进的作用

数组过滤

var book={ 
    "title":"book title", 
    authors:[ "one", "two", "three" ],
    edition:2, 
    year:2021 
}; 
var JSONStr=JSON.stringify(book,["title","year","other"]);
console.log(JSONStr);//{"title":"book title","year":2021} 
console.log(typeof JSONStr);//string

JSON.stringify() 的第二个参数是一个数组,其中包含三个字符串: "title"、"year"、"other"。这两个属性与将要序列化的对象中的属性是对应的,因此在返回的结果字符串中,就只会包含这两个属性;因为源数据中没有other这个键值对;匹配不到,就会忽略掉;

函数过滤

  var book = {
    "title": "JSON",
    "authors": ["one", "two", "three"],
  };
  var JSONStr = JSON.stringify(book, function (key, value) {
    switch (key) {
      case "authors":
        return value.join("+++++"); //如果键为 "authors" ,就将数组连接为一个字符串 
        // console.log(JSONStr);//{"title":"JSON","authors":"one+++++two+++++three",} 
    }
  }

函数过滤器根据传入的来决定结果

字符串缩进

注意 如果 space 是一个数字,则返回值文本在每个级别缩进指定数目空格,如果 space 大于 10,则文本缩进 10 个空格(前10个)。

var book={
    "title":"JSON",
    authors:[
        "one",
        "two",
        "three"
    ],
    year:2021
};
var JSONStr=JSON.stringify(book,null,4);
console.log(JSONStr);

输出结果如下:

{
    "title": "JSON",
    "authors": [
        "one",
        "two",
        "three"
    ],
    "year": 2021
}

// 默认
{"title":"book title","authors":["one","two","three"],"year":2021}

也可以用字符替换空格

var JSONStr=JSON.stringify(book,null,"+ + ");

输出结果如下:

{
+ + "title": "JSON",
+ + "authors": [
+ + + + "one",
+ + + + "two",
+ + + + "three"
+ + ],
+ + "year": 2021
}

JSON.parse()

用法 将数据转换为 JavaScript 对象(接收服务器数据时一般是字符串)

var JSONStr1 = '{title: "JSON",authors: ["Jack"],age: 18}';
var JSONStr2 = '{"title": "JSON","authors": ["Jack"],"age": 18,year: 2021}';
var JSONStr3 = '{"title": "JSON","authors": ["Jack"],"age": 18}';
var JSONStr4 = '{"title": "JSON","authors": ["Jack"],"age": 18,"year": 2021,"testUndefined":undefined}';

//var JSONObj1 = JSON.parse(JSONStr1);      // 报错啦,属性值没有""
//var JSONObj2 = JSON.parse(JSONStr2);      // 报错啦,属性值没有全部用""
var JSONObj3 = JSON.parse(JSONStr3);        // 成功
//var JSONObj4 = JSON.parse(JSONStr4);        // 报错啦,不能含有undefined,function等数据
console.log(JSONObj3); //{"title":"JSON","authors":["Jack"],"age":18,"year":2021}

异常

1. 解析数据

与JSON.stringify()同样不能存储 Date 对象。

如果你需要存储 Date 对象,需要将其转换为字符串

之后将字符串转换为 Date 对象。

var text = '{ "name":"JSON", "initDate":"2021-06-18"}';
var obj = JSON.parse(text);
obj.initDate = new Date(obj.initDate);
console.log(obj); // {name: "Runoob", initDate: Fri Jun 18 2021 08:00:00 GMT+0800 (中国标准时间)}

2. 解析函数

JSON 不允许包含函数,但你可以将函数作为字符串存储,之后再将字符串转换为函数。

可选参数 snipaste20210607_140332.png

var text = '{ "name":"JSON", "initDate":"2021-06-18"}';
var obj = JSON.parse(text, function (key, value) {
	if (key == "initDate") {
	    return new Date(value);
	} else {
	    return value;
        }
});
console.log(obj);  // {name: "JSON", initDate: Fri Jun 18 2021 08:00:00 GMT+0800 (中国标准时间)}