JSON是一种轻量级的数据交换格式,相对于xml,它体积小,使用非常简便,受到了开发人员们的热烈欢迎,是目前主流的一种格式。
json中可以保存简单值,如字符串,数值,布尔值,unll,也可以保存对象以及数组,但不支持undefined和函数。
var json = {
"name" : "json",
"age" : 1,
"arr" : [1,{},3]
}
以上就是json的语法格式,与js的对象与数组字面量很相似,但需要注意的是,json规定对象的键名必须加上双引号,并且,字符串值也必须加上双引号,否则会报错。
对象的键值可以是简单值,也可以是复杂数据类型,通过复杂数据类型之间的相互嵌套,json就可以表示出足够满足我们需求的数据结构。
json数据结构的最外层不一定是一个对象,当然也可以是一个数组,通常情况下,最外层的数据类型就是这两种。
JSON对象
JSON对象有两个方法,分别是stringify方法,用来将js对象转换为json字符串,和parse方法,用来将json格式的字符串转换为原生JavaScript值。
var json = {
name : 'json',
boolean : false,
null : null,
number : 1,
arr : [1,2,3]
}
JSON.stringify(json) //{"name":"json","boolean":false,"null":null,"number":1,"arr":[1,2,3]}
在js对象被序列化为json格式的字符串结果中,属性都被加上了双引号,原本用单引号表示的字符串也被替换成了双引号,序列化的结果中也不包含空格与缩进。
var json = {
name : undefined,
fun : function () {}
}
JSON.stringify(json) // {}
根据转换后的结果可以看到,在对于不支持的数据类型时,undefined和函数不会被序列化,而是直接被忽略,结果序列化的结果只是一个空对象。
使用parse方法,则可以将传入的json字符串转换为相应的原生js值。
var obj = JSON.parse('{"name" : "json","boolean" : false,"null" : null,"number" : 1,"arr" : [1,2,3]}');
obj.name //'json'
需要注意的是,虽然parse方法接受的json字符串是一样的,但每次序列化后的js对象都是独立的。
var json = '{"name" : "json","boolean" : false,"null" : null,"number" : 1,"arr" : [1,2,3]}';
var obj1 = JSON.parse(json);
console.log(obj1.name) //json
var obj2 = JSON.parse(json);
console.log(obj2.name) //json
console.log(obj2 === obj1) //false
通过这样的特性,可以实现对象的拷贝:
var obj = {
name : 'obj',
age : 1,
arr : [1,2,3]
}
var objclone = JSON.parse(JSON.stringify(obj));
obj.arr === objclone.arr //false
当然这样方法的缺陷显而易见,当js对象被序列化成json字符串时,如果其中包含如undefined或函数这样的数据类型时,将会被忽略。
stringify方法的额外参数
stringify方法还可以接受第二和第三个参数,第二个参数是一个过滤器,可以是一个数组或者函数。
var json = {
name : 'json',
boolean : false,
null : null,
number : 1,
arr : [1,2,3]
}
JSON.stringify(json,["name","boolean"]) //{"name":"json","boolean":false}
通过传入一个数组,那么该方法会只将数组中指定的键名放入序列化结果中。
如果是一个函数,那么每个键和值会被传入回调函数中,函数的返回值会把相应的键值替换掉,如果返回undefined,那么该属性会被忽略,该键值对不会出现在序列化结果中。
var obj = {
"username":"hello world",
"age":20,
"height":"185cm",
"address":"Shanghai"
}
JSON.stringify(obj, function(key, val){
switch(key){
case "username":
return "javascript";
case "age":
return 10;
case "height":
return undefined; //height属性会被忽略
default:
return val;
}
});
//结果:{"username":"javascript","age":10,"address":"Shanghai"}
JavaScript对象在序列化之后不会保留空格与缩进,但使用第三个参数可以用来控制缩进
var jsonText = JSON.stringify(json,null,3)
以上代码表示在每个级别上缩进3个空格
结果:
{
"name": "json",
"boolean": false,
"null": null,
"number": 1,
"arr": [
1,
2,
3
]
}
如果给定参数是一个字符串,则这个字符串将被用做缩进字符。
var jsonText = JSON.stringify(json,null,'__')
结果:
{
__"name": "json",
__"boolean": false,
__"null": null,
__"number": 1,
__"arr": [
____1,
____2,
____3
__]
}
toJSON方法
当stringify方法接受的对象中存在toJSON方法时,会将方法中返回的值进行序列化处理。
var json = {
"name" : 'json',
"boolean" : false,
"null" : null,
"number" : 1,
"arr" : [1,2,3],
toJSON : function () {
return {name : this.name,age:this.number};
}
}
JSON.stringify(json) //{"name":"json","age":1}
toJSON方法中返回的值将会被传入过滤器函数中,因此可以在过滤器函数中对toJSON方法的返回值进行处理:
var json = {
"name" : 'json',
"boolean" : false,
"null" : null,
"number" : 1,
"arr" : [1,2,3],
toJSON : function () {
return {name : this.name,age:this.number};
}
}
JSON.stringify(json,function (key,value) {
switch(key){
case "name":
return "JSON";
case "age":
return 10;
default:
return value;
}
})
结果:
{"name":"JSON","age":10}
parse方法的第二个参数
parse方法的第二个参数和stringify方法的过滤器函数相似,该函数将在每个键值对上调用,并接受当前的键名与键值为参数,如果该方法返回undefined,那么当前键值将不会出现在序列化后的结果中,如果返回的是其他值,则该值会用作当前键的键值。
var json = {
"name" : 'json',
"boolean" : false,
"null" : null,
"number" : 1,
"arr" : [1,2,3],
"date" : new Date(2011,11,1)
}
var jsonText = JSON.stringify(json)
结果:
{"name":"json","boolean":false,"null":null,"number":1,"arr":[1,2,3],"date":"2011-11-30T16:00:00.000Z"}
上面的例子中,json对象中的Date对象被序列化后成了普通的json字符串,下面在使用parse方法对其进行序列化为JavaScript对象的时候,使用了处理函数,将date对象进行还原。
var jsonObj = JSON.parse(jsonText,function (key,value) {
if (key === 'date') {
return new Date(value);
}else {
return value;
}
})
jsonObj.date.getFullYear() //2011