JSON是javascript的一个严格的子集,但它不支持变量、函数或对象实例,它是一种表示结构化数据的格式。
语法
JSON的语法可以表示以下三种类型的值:
- 简单值:字符串、数值、布尔值和null。不支持undefined;
- 对象:对象的属性值可以是简单值,也可以是对象或数组;
- 数组:数组的值也可以是任意类型——简单值、对象或数组。
简单值
最简单的JSON数据形式就是简单值,但是它一般只作为整个数据结构的一部分。
下面这些,都是有效的JSON数据:
5
"hello"
注意:JSON字符串必须使用双引号,单引号会导致语法错误。
对象
JSON可以这样表示:
{
"name":"Bob",
"age":12
}
注意,它与javascript对象字面量有以下三点不同:
- 没有变量声明(JSON中没有变量的概念);
- 在{}的末尾没有用分号结束(它不是javascript语句,所以不需要分号);
- JSON对象中的属性必须加双引号!
JSON属性的值可以是简单值,也可以是复杂类型值:
{
"name":"Bob",
"age":12,
"school":{
"name":"schoolname",
"location":"FJ"
}
}
数组
JSON数组就是采用javascript的数组字面量形式:
[25,"hello",true]
同样注意,JSON数组也没有变量和分号。
把数组跟对象结合起来,便会构成更复杂的数据结构:
[
{
"title":"title1",
"authors":[
"author1"
],
"edition":3,
"year":2011
},
{
"title":"title2",
"authors":[
"author2","author22"
],
"edition":2,
"year":2012
}
]
对象和数组通常是JSON数据结构的最外层(不是强制规定),利用它们能创造出各种各样的数据结构。
解析与序列化
JSON数据结构可以解析为有用的javascript对象,并且相对容易实现,因此,JSON成了web服务开发中交换数据的标准。
JSON对象
JSON对象有两个方法:stringify()和parse()。
stringify()用于把javascript对象序列化为JSON字符串:
var book={
title:"title1",
authors:[
"authors1"
],
edition:3,
year:2011
};
var jsonText=JSON.stringify(book);
console.log(jsonText);
//{"title":"title1","authors":["authors1"],"edition":3,"year":2011}
默认情况下,JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进。还必须注意,在序列化javascript对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外,值为undefined的任何属性也都会被跳过。结果中最终都是值为有效JSON数据类型的实例属性。
parse()用于把JSON字符串解析为原生的javascript值:
var book={
title:"title1",
authors:[
"authors1"
],
edition:3,
year:2011
};
var jsonText=JSON.stringify(book);
var bookCopy=JSON.parse(jsonText);
console.log("title:"+bookCopy.title+";authors:"+bookCopy.authors+";edition:"+bookCopy.edition+";year:"+bookCopy.year);
//title:title1;authors:authors1;edition:3;year:2011
注意,虽然bookcopy与book具有相同的属性,当它们是两个独立的对象。没有任何关系。
如果传给JSON.parse()字符串不是有效的JSON,该方法会抛出错误。
序列化选项
JSON.stringify()除了要序列化的javascript对象外,还可以接收另外两个参数,这两个参数用于指定以不同方式序列化javascript对象。
第一个参数是个过滤器,可以是一个数组,也可以是一个函数;
第二个参数是一个选项,表示是否在JSON字符串中保留缩进。
1.过滤结果
如果过滤器参数是数组,那么JSON.stringify()的结果中只包含数组中列出来的属性:
var book={
title:"title1",
authors:[
"authors1"
],
edition:3,
year:2011
};
var jsonText=JSON.stringify(book,["title","edition"]);
console.log(jsonText); //{"title":"title1","edition":3}
如果第二个参数是函数,那么传入的函数接收两个参数:属性名和属性值。
通过属性名可以知道如何处理要序列化的对象中的属性。属性名只能是字符串,而在值并非键值对结构的值时,键名可以是空字符串。
为了改变序列化的结果,函数返回的值就是相应的键的结果值。注意,如果函数返回了undefined,那么相应的属性会被忽略(因为JSON不支持undefined)。
var book={
title:"title1",
authors:[
"authors1","authors2"
],
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;
}
});
console.log(jsonText);
//{"title":"title1","authors":"authors1,authors2","year":5000}
2.字符串缩进
JSON.stringify()的第三个参数是用于控制结果中的缩进和空白字符的。如果这个参数是一个数值,那它表示每个级别缩进的空格数(注意,最大的缩进格数为10,所有大于10的值都会自动被转换为10):
var book={
title:"title1",
authors:[
"authors1","authors2"
],
edition:3,
year:2011
};
var jsonText=JSON.stringify(book,null,4);
console.log(jsonText);
/*
{
"title": "title1",
"authors": [
"authors1",
"authors2"
],
"edition": 3,
"year": 2011
}
*/
如果缩进参数是一个字符串而不是数值,则这个字符串将在JSON字符串中被用作缩进字符(不再使用空格):
var book={
title:"title1",
authors:[
"authors1","authors2"
],
edition:3,
year:2011
};
var jsonText=JSON.stringify(book,null,"--");
console.log(jsonText);
/*
{
--"title": "title1",
--"authors": [
----"authors1",
----"authors2"
--],
--"edition": 3,
--"year": 2011
}
*/
缩放字符串最长也不能超过10个字符串长。如果字符串长度超出了10个,结果中也只出现前10个字符。
3.toJSON()方法
有时,如果JSON.stringify()不能满足某些对象进行自定义序列化的需求,那么可以通过对象上调用toJSON(),返回其自身的JSON数据格式。
原生的Date对象有一个toJSON()方法,能将javascript的Date对象自动换成ISO 8601日期字符串。
可为任何对象添加toJSON方法:
var book={
title:"title1",
authors:[
"authors1","authors2"
],
edition:3,
year:2011,
toJSON:function(){
return this.title;
}
};
var jsonText=JSON.stringify(book);
console.log(jsonText); //"title1"
把一个对象传入JSON.stringify(),序列化该对象的顺序如下:
- 如果存在toJSON()方法而且能通过它取得有效的值,则用该方法。否则,按照默认顺序执行序列化。
- 如果提供了第二个参数,应用这个函数过滤器。传人函数过滤器的值是第一步返回的值。
- 对第二步返回的每个值进行相应的序列化。
- 如果提供了第三个参数,执行相应的格式化。
解析选项
JSON.parse()方法可可以接收另一个参数,该参数是一个函数,将在每个键值对上调用。这个函数被称为还原函数。它也接收两个参数,一个键和一个值,而且需要返回一个值。
如果还原函数返回undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入结果中。如:
var book={
title:"title1",
authors:[
"authors1","authors2"
],
edition:3,
year:2011,
releaseDate:new Date(2011,11,1)
};
var jsonText=JSON.stringify(book);
var bookCopy=JSON.parse(jsonText,function(key,value){
if(key=="releaseDate"){
return new Date(value);
}else{
return value;
}
})
console.log(bookCopy.releaseDate.getFullYear()); //2011