js学习笔记:JSON
曾经,XML是互联网上传输结构化数据的事实标准。但是XML太过繁琐、冗长。为解决这个问题,JSON出现了。JSON是js的一个严格的子集,利用了js中的一些模式来表示结构化数据。关键JSON是一种数据格式,而不是一种编程语言,虽然有相同的语法形式,但JSON并不从属于js,很多语言都有针对JSON的解析器和序列化器。
语法JSON的语法可以表示以下三种类型的值:简单值:使用与js相同的语法,可以在JSON中表示字符串、数值、布尔值和null。但JSON不支持特殊值undefined。
对象:对象作为一种复杂数据类型,表示的是一组无序的键值对儿。而每个键值对中的值可以是简单值,也可以是复杂数据类型的值。
数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型——简单值、对象或数组。
JSON不支持变量、函数或对象实例,它就是一种表示结构化数据的格式。
简单值最简单的JSON数据形式就是简单值。如:[code]5 //数值 "hello world" //字符串
js字符串与JSON字符串最大区别就是,JSON字符串必须使用双引号(单引号会导致语法错误)。布尔值和null也是有效的JSON形式。
但是在实际应用中,JSON更多地用来表示更复杂的数据结构,而简单值只是整个数据结构中的一部分。
对象JSON中的对象与js字面量稍微有一些不同。 下面是一个js中的字面量:
[code]var person = { name:"nicholas", age:29 };在JSON中的对象要求给属性加双引号,JSON表示形式如下:
[code]{ "name":"nicholas", "age":29 }与js的对象字面量相比,JSON对象有几个地方不一样:
没有声明变量(JSON中没有变量的概念)。
没有末尾的分号(因为这并不是js语句,不用加分号)
对象的属性必须加双引号属性的值可以是简单值,也可以是复杂类型值,因此可以像下面这样在对象中嵌入对象:
[code]{ "name":"nicholas", "age":29, "school":{ "name":"college", "location":"NY" } }数组JSON中的第二种复杂数据类型是数组。JSON数组采用的就是js中的数组字面量形式。
下面是js中的数组字面量:
[code]var values = [25,"hi",true];在JSON中,可以采用同样的语法表示同一个数组:
[code][25,"hi",true]同样要注意,JSON数组也没有变量和分号。
把数组和对象结合起来,可以构成更复杂的数据集合:
[code][ { "title":"aaa", "authors":[ "aa" ], "edition":3, "year":2011 }, { "title":"bbb", "authors":[ "aa", "bb" ], "edition":2, "year":2009 } ]解析与序列化JSON之所以流行,因为可以把JSON数据结构解析为有用的js对象。与XML数据结构要解析为DOM文档而且从中提取数据极为麻烦相比,JSON可以解析为js对象的优势极其明显。
JSON对象早期的JSON解析器基本上就是使用js的eval()函数。由于JSON是js语法的子集,因此eval()函数可以解析、解释并返回js对象和数组。ECMAScript5对解析JSON的行为进行规范,定义了全局对象JSON。
JSON对象有两个方法:
stringify():把js对象序列化为JSON字符串
parse():把JSON字符串解析为原生js值。
[code]var book = { "title":"aaa", "authors":[ "aa" ], "edition":3, "year":2011 }; var jsonText = JSON.stringify(book); //"{"title":"aaa","authors":["aa"],"edition":3,"year":2011}"这个例子使用JSON.stringify( )把一个js对象序列化为一个JSON字符串,然后将它保存在变量jsonText中。
默认情况下,JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进,就像上面展示的那样。在序列化js对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外,值为undefined的任何属性也都会被跳过。最终结果中的值都是有效的JSON数据类型。
将JSON字符串直接传递给JSON.parse()就可以得到相应的js值。
[code]var bookCopy = JSON.parse(jsonText);bookCopy是一个与book类似的对象。虽然book与bookCopy有相同的属性,但它们两个是独立的,没有任何关系的对象。
如果传给JSON.parse()的字符串不是有效的JSON,该方法会抛出错误。
序列化选项实际上,JSON.stringify()除了要序列化的js对象外,还可以接受另外两个参数,这两个参数用于指定以不同的方式序列化js对象。 第一个参数是一个过滤器,可以是一个数组,也可以是一个函数。
第二个参数是一个选项,表示是否在JSON字符串中保持缩进。
过滤结果如果过滤器参数是数组,那么JSON.stringify()的结果中将只包含数组中列出的属性。[code]var book = { "title":"aaa", "authors":[ "aa" ], "edition":3, "year":2011 }; var jsonText = JSON.stringify(book,["title","edition"]);
第二个参数是一个数组,包含两个字符串。这两个属性与将要序列化的对象中的属性是对应的,因此在返回的结果字符串中,就只会包含这两个属性:
[code]"{"title":"aaa","edition":3}"如果第二个参数是函数,行为会稍有不同。传入的函数接收两个参数,属性名和属性值。根据属性名可以知道应该要如何处理序列化的对象中的属性。属性名只能是字符串,而在并不是键值对儿的结构中,键名可以是空字符串。
为了改变序列化对象的结果,函数返回的值就是相应键的值。但是如果函数返回了undefined,那么相应的属性会被忽略。
[code]var book = { "title":"aaa", "authors":[ "aa", "bb" ], "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; } });这里,函数过滤器根据传入的键来决定结果。
如果键为“authors”,就将数组连接为一个字符串;
如果键为“year”,就将其值设置为5000;
如果键为“edition”,通过返回undefined删除该属性;
最后,一定要提供default项,此时返回传入的值,以便其他值都能正常出现在结果中。 序列化后的字符串如下:
[code]"{"title":"aaa","authors":"aa,bb","year":5000}"要序列化的对象中的每一个对象都要经过过滤器,因此数组中的每个带有这些属性的对象经过过滤之后,每个对象都只会包含”title”,”authors”,”year”这三个属性。
字符串缩进JSON.stringify()方法的第三个参数用于控制结果中的缩进和空格符。 如果这个参数是一个数值,那它表示的是每个级别缩进的空格数。
例如,要在每个级别缩进4个空格:
[code]var book = { "title":"aaa", "authors":[ "aa", "bb" ], "edition":3, "year":2011 }; var jsonText = JSON.stringify(book,null,4);结果如下所示: