JSON
一、语法
JSON语法可以表示以下三种类型的值:
1)简单值:字符串,数值,布尔值和null。不支持undefined;
2)对象:一组无序的键值对儿。每个键值对儿中的值可以是简单值也可以是复杂数据类型的值。
3)数组:一组有序的值得列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型——简单值、对象或数组。
1. 简单值
5 “Hello world!”
JS字符串与JSON字符串的最大区别在于,JSON字符串必须使用双引号(单引号会导致语法错误)。
布尔值和null也是有效的JSON形式。
2. 对象值
{ “name”:”Nicholas”, “age”:29 }
与JS的对象字面量相比,JSON对象有两个地方不一样。首先,没有声明变量(JSON中没有变量的概念)。其次,没有末尾的分号。对象的属性必须加双引号,这在JSON中是必需的。属性的值可以是简单值也可以是复杂类型值,因此可以像下面这样在对象中嵌入对象:
{ “name”:”Nicholas”, “age”:29, “school”:{ “name”:”Merrimack”, “location”:”North” } }
3. 数组
JSON中的第二种复杂数据类型是数组。JSON数组采用的就是JS中的数组字面量形式。
[25,”hi”,true]
JSON数组也没有变量和分号。把数组和对象结合起来,可以构成更复杂的数据集合。
二、解析与序列化
1.JSON对象
早期的JSON解析器基本上就是使用JS的eval()函数。由于JSON是JS语法的子集,因此eval()函数可以解析、解释并返回JS对象和数组。
JSON对象有两个方法:stringify()和parse()。分别用于把JS对象序列化为JSON字符串和把JSON字符串解析为原生JS值。
1)JSON.stringify()把JS对象序列化为JSON字符串
var book={ title:”Professional”, authors:[“Nic”], edition:3, year:2011 }; var jsonText=JSON.stringify(book);
默认情况下,JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进,因此保存在jsonText中的字符串如下:
{“title”:”professional”,”authors”:[“Nic”],”edition”:3,”year”:2011}
在序列化JS对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外值为undefined的任何属性也都会被跳过。结果中最终都是值为有效JSON数据类型的实例属性。
2) JSON.parse()把JSON字符串解析为原生JS值
将JSON字符串直接传递给JSON.parse()就可以得到相应的JS值。
var bookCopy=JSON.parse(jsonText);
如果传给JSON.parse()的字符串不是有效的JSON,该方法会抛出错误。
2. 序列化选项
JSON.stringify()除了要序列化的JS对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化JS对象。第一个参数是个过滤器,可以是数组,也可以是函数;第二个参数是一个选项,表示是否在JSON字符串中保留缩进。单独或组合使用这两个参数,可以更全面深入地控制JSON的序列化。
1)过滤结果
如果过滤参数是数组,那么JSON.stringify()的结果中将只包含数组中列出的属性。
var book={ "title":"Profess", "author":["Nic"], edition:3, year:2011 }; var jsonText=JSON.stringify(book,["title","edition"]); //{“title”:”Profess”,”edition”:3}
如果传入的是函数,行为稍有不同。传入的函数接收两个参数,属性名和属性值。根据属性名可以知道应该如何处理要序列化的对象中的属性。属性名只能是字符串,而在值并非键值对儿结构的值时,键名可以是空字符串。为了改变序列化对象的结果,函数返回的值就是相应键的值。但是如果函数返回了undefined,那么相应的属性会被忽略。
var book={ “title”:”Profess”, “author”:[“Nic”,”Mary”], edition:3, year: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; } }) //输出 {“title”:”Profess”,”authors”:”Nic.Mary”,”year”:5000}
最后一定要提供default项,此时返回传入的值,以便其他值都能正常出现在结果中。实际上,第一次调用这个函数过滤器,传入的键是一个空字符串,而值就是book对象。
2) 字符串缩进
JSON.stringify()方法的第三个参数用于控制结果中的缩进和空白符。如果这个参数是一个数值,那他表示的是每个级别缩进的空格数。
如上例: var jsonText=JSON.stringify(book,null,4);
保存在jsonText的字符串如下:
{
“title”:”Profess”,
“authors”:[“Nic”,”Mary”],
“edition”:3,
“year”:2011
}
只要传入有效的控制缩进的参数值,结果字符串就会包含换行符。(只缩进而不换行意义不大)。最大缩进空格数为10,所有大于10的值都会自动转换为10.
如果缩进参数是一个字符串而非数值,则这个字符串将在JSON字符串中被用作缩进字符(不再使用空格)。在使用字符串的情况下,可以将缩进字符设置为制表符,或者两个短划线之内的任意字符。
var jsonText=JSON.stringify(book,null,”--”);
缩进字符串最长不能超过10个字符长。如果字符串长度超过了10个,只出现前10个字符。
3)toJSON()方法
可以为任何对象添加toJSON()方法
var book={ "title":"Profess", "authors":['Nic','Mary'], edition:3, year:2011, toJSON:function(){ return this.authors; } } var jsonText=JSON.stringify(book); alert(jsonText); // [‘Nic’,’Mary’]
toJSON()可以作为函数过滤器的补充,因此理解序列化的内部顺序十分重要。假设把一个对象传入JSON.stringify(),序列化该对象的顺序如下:
1)如果存在toJSON()方法而且通过它可以取得有效的值,则调用该方法。否则返回对象本身。
2)如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第(1)步返回的值。
3)对第2)步中返回的每个值进行相应序列化
3)如果提供了第三个参数,执行相应格式化
3.解析选项
JSON.parse()也可以接受另一个参数,该参数是一个函数,将在每个键值对儿上调用。这个函数被称为还原函数。它们都接受两个参数,一个键和一个值,而且都需要返回一个值。
如果还原函数返回undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入到结果中。在将日期字符串转换为Date对象时,经常要用到还原函数。
var book={ "title":"Profess", "authors":['Nic','Mary'], edition:3, year:2011, releaseDate:new Date(2011,11,1) } var jsonText=JSON.stringify(book); alert(jsonText); var bookCopy=JSON.parse(jsonText,function(key,value){ if(key=='releaseDate'){ return new Date(value); }else{ return value; } }); alert(bookCopy.releaseDate.getFullYear());