ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 11.1 语法 .JSON语法可以表示以下三种类型的值: * 简单值:使用与JavaScript相同的语法,可以在JSON中表示字符串(双引)、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity, -Infinity和undefined)。但JSON不支持JavaScript中的特殊值undefined。 * 对象:对象作为一种复杂数据类型,表示的是一组无序的键值对。而每个键值对中的值可以是简单值,也可以是复杂数据类型的值。(键名必须在双引号内) * 数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。(最后成员不加逗号) ### 11.1.1 简单值 最简单的JSON数据形式就是简单值。 ~~~ 5 "Hello world" null true false ~~~ 上面的都是有效的JSON数据。 ### 11.1.2 对象 JSON中的对象与JavaScript中的对象字面量基本一样,除了JSON中的对象要求**对象的属性一定要加上双引号**。 JavaScript中的对象字面量: ~~~ 标准形式 var object = { name: "Nicholas", age: 29; }; 或 var object = { "name": "Nicholas", "age": 29; }; ~~~ JSON中的对象字面量(没有声明,对象的属性必须加双引号,末尾没分好): ~~~ { "name": "Nicholas", "age": 29; } ~~~ 当然,可以使用嵌套对象: ~~~ { "name": "Nicholas", "age": 29, "school": { "name" : "Merrimack College", "location": "North Andover, MA" } } ~~~ 上面有两个同名(name)属性,这是没问题的,因为它们属于不同的对象。 **不同对象可以有同名属性,但同一对象内不能出现同名属性。** ### 11.1.3 数组 JSON数组采用的是JavaScript中的数组字面量,**也没有变量和分号**。 ~~~ { //JavaScript: var values = [25,"hi",true]; //JSON [25,"hi",true] } ~~~ **还可以在数组中放对象,对象中放数组。** ## 11.2 解析与序列化 JSON在JavaScript中流行的原因是JSON数据结构可以解析成有用的JavaScript对象。 ### 11.2.1 JSON对象 JSON是JavaScript语法的子集,因此eval()函数可以解析、解释并返回JavaScript对象和数组。 JSON对象有两个方法:`stringify()和parse()`。 JSON.stringify()把**JavaScript对象序列化为一个JSON字符串**(不包含任何空格字符或缩进)。 注意:在序列化JavaScript对象时,所有函数及原型成员都会被有意忽略,不体现在结果中,而且值为undefined的任何属性也会被跳过,还有正则对象会被转成空对象。最终返回来的值为有效的JSON格式。 ~~~ var data = { name: 'tg', age: 1, books: [ "Javascript", 2], location:{ name: "gz", }, test: function(){}, sex: undefined }; console.log(JSON.stringify(data)); //{"name":"tg","age":1,"books":["Javascript",2],"location":{"name":"gz"}} ~~~ ### 11.2.2 序列化选项 JSON.stringify()还接受额外两个参数,用于指定以不同的方式序列化JavaScript对象。 第二个参数是个过滤器,可以是一个数组,也可以是一个函数;第三个参数是一个选项,表示是否在JSON字符串中保留缩进。 **1. 过滤结果** 当传入的参数是**数组**时,那么JSON.stringify()的结果中将只包含数组中列出的属性。 ~~~ var data = { name: 'tg', age: 1, books: [ "Javascript", 2], location:{ name: "gz", }, test: function(){}, sex: undefined }; console.log(JSON.stringify(data,["name","books"])); //{"name":"tg","books":["Javascript",2]} ~~~ 在上面的例子中,传给JSON.stringify()的第二个参数是一个数组,其中包含两个字符串:“name”和“books”,这两个属性与将要序列化的对象中的属性是对应的,因此在返回的结果字符串中,就只会包含这两个属性(如上结果)。 第二个参数还可以是**函数**,它接收两个参数:属性(键)名和属性值,返回的值就是相应键的值(它改变了序列化对象的结果)。 属性名只能是字符串,而在值并非键值对的值时,键名可以是空字符串。 ~~~ var jsonText = JSON.stringify(data,function(key, value){ if(key == 'books'){ return value.join(','); }else{ return value; } }); console.log(jsonText); //{"name":"tg","age":1,"books":"Javascript,2","location":{"name":"gz"}} ~~~ 在上面的例子中,如果键名为"books",就将数组连成一个字符串,否则,返回原值。 注意:如果函数返回了undefined,那么相应的属性会被忽略。 **2. 字符串缩进** JSON.stringify()方法还可以接收第三个参数,用于控制结果中的缩进和空白符。如果这个参数是数值,那它表示的是每个级别缩进的空格数。比如,要在每个级别缩进4个空格: ~~~ var data = { name: 'tg', age: 1, books: [ "Javascript", 2], location:{ name: "gz", }, test: function(){}, sex: undefined }; console.log(JSON.stringify(data, null, 4)); // 结果 { "name": "tg", "age": 1, "books": [ "Javascript", 2 ], "location": { "name": "gz" } } ~~~ 当传入有效的控制缩进的参数值时,结果字符串就会自动包含换行符。不过要注意:最大缩进空格数为10,所有大于10的值都会自动转换为10. 如果缩进参数是一个字符串而非数值,则这个字符串将在JSON字符串中**被用作缩进字符**。 ~~~ var data = { name: 'tg', age: 1, books: [ "Javascript", 2], location:{ name: "gz", }, test: function(){}, sex: undefined }; console.log(JSON.stringify(data, null, 4)); // 结果 { --"name": "tg", --"age": 1, --"books": [ ----"Javascript", ----2 --], --"location": { ----"name": "gz" --} } ~~~ 注意:缩进字符串最长不能超过10个字符长,如果超过了10个,结果中只会显示10个字符。 **3. toJSON()方法** 如果JSON.stringify的参数对象有自定义的toJSON方法,那么JSON.stringify会**使用这个方法的返回值作为参数**,而忽略原对象的其他属性。 ~~~ var data = { name: 'tg', age: 1, toJSON:function(){ var data = { name: this.name }; return data; } }; console.log(JSON.stringify(data)); //{"name":"tg"} ~~~ 在上面的代码中,我们给data对象定义了一个toJSON()方法,该方法返回name的值。 可以为任何对象添加toJSON()方法,让toJSON()方法返回任何序列化的值。 假设将一个对象传入JSON.stringify(),序列化对象的顺序如下: 1. 如果存在toJSON()方法而且能通过它取得有效的值,则调用该方法,否则,按默认顺序序列化。 2. 如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第1步返回的值 3. 对第2步返回的每个值进行相应的序列化 4. 如果提供了第三个参数,执行相应的格式化 ### 11.2.3 解析选项 JSON.parse方法用于**将JSON字符串转化成原生的JavaScript对象。** ~~~ var jsonText = '{"name":"tg","age":1,"books":["Javascript",2],"location":{"name":"gz"}}'; console.log(JSON.parse(jsonText)); //返回对象 { name: 'tg', age: 1, books: [ "Javascript", 2], location:{ name: "gz", } }; ~~~ 如果传入的字符串不是有效的JSON格式,则会报错。 JSON.parse()还可以接收第二个参数,该参数是一个函数,将在每个键值对上调用。 ~~~ var jsonText = '{"name":"tg","age":1,"books":["Javascript",2],"location":{"name":"gz"}}; var o = JSON.parse(jsonText,function(key, value){ if(key == "name"){ return "Hello"; } return value; }); console.log(o.name); // Hello ~~~ 在上面的例子中,在解析时,当遇到键名是“name”时,就将相应的值替换成"Hello",最终返回的name就是"Hello"。 如果函数返回undefined,则表示要从结果中删除相应的键,如果返回其他值,则将其放入到结果中。