JavaScript对象和JSON
JSON(JavaScript Object Notation)
,指JavaScript
的对象表示法,它本身是个字符串,是一种数据交换格式,并非对象。通常所提的JSON
对象实际是JSON
字符串解析成对象的结果,或是浏览器window
对象下的JSON
对象。
而且JSON
不止用于JavaScript
中,其广泛用于数据交换。
#JSON和JavaScript对象
一个JSON
文件,或一段JSON
字符串,通常是这样的:
[{
"name": "用户权限管理",
"code": "99990002",
"icon": "modicon-1",
"items": [{
"name": "模块权限",
"code": "999900020009",
"url": "",
"isBlank": false,
"items": [{
"name": "向导模板",
"code": "9999000200090003",
"url": "pages/accLayoutTest.html",
"isBlank": false,
"items": []
}, {
"name": "模块管理我们的",
"code": "9999000200090001",
"url": "pages/contentPageTest.html",
"isBlank": false,
"items": []
}]
}]
}, ... ]
而这样类似的JavaScript
对象则是这样的:
var menuData = [{
name: "用户权限管理",
code: "99990002",
icon: "modicon-1",
items: [{
name: "模块权限",
code: "999900020009",
url: "",
isBlank: false,
items: [{
name: "向导模板",
code: "9999000200090003",
url: "pages/accLayoutTest.html",
isBlank: false,
items: []
}, {
name: "模块管理我们的",
code: "9999000200090001",
url: "pages/contentPageTest.html",
isBlank: false,
items: []
}]
}]
}, ...]
两者非常的相似,所不同的是就是JavaScript
对象中属性名,也就是对象的key
值是可以没有引号的,其值为字符串时,使用''
和""
包裹均可。 因此我们很多人将第一段代码块里所写的JSON
称为JSON对象,实际上,它并不是一个对象,只是一个单纯的字符串而已,但是它符合JSON
的语法规则,可以很方便地转化为JavaScript
对象,或者方便地用于数据交换。
以下我们来了解一下JSON
。
#JSON语法
JSON语法规则
JSON 语法是 JavaScript 对象表示语法的子集,其基本原则如下:
数据在键值对中
数据由逗号分隔
花括号保存对象
方括号保存数组
JSON的值
数字(整数或浮点数)
字符串(在双引号中)
逻辑值(
true
或false
)数组(在方括号中
[]
)对象(在花括号中
{}
)null
JSON
作为一种数据交换格式,为了保证其能被正确方便的解析,其格式有严格的要求,必须遵循以下规则:
复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
简单类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和
null
(不能使用NaN
,Infinity
,-Infinity
和undefined
)。字符串必须使用双引号表示,不能使用单引号。
对象的键名必须放在双引号里面。
数组或对象最后一个成员的后面,不能有逗号。
数值前不能加0。
以下是合法的JSON
格式示例:
["one", "two", "three"]
{
"one": 1,
"two": 2,
"three": 3
}
{
"names": [
"张三",
"李四"
]
}
[
{ "name": "张三" },
{ "name": "李四" }
]
下面这些就是不合法的:
{
name: "张三",
'age': 32
} // 属性名必须使用双引号
[32, 64, 128, 0xFFF] // 不能使用十六进制值
{
"name": "张三",
"age": undefined
} // 不能使用undefined
{
"name": "张三",
"birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
"getName": function() {
return this.name;
}
} // 不能使用函数和日期对象
{
"name": "李四",
"age": 018
} // 数值前不能有0
以上代码中为了指出错误所在,使用了
JavaScript
的注释法,实际JSON
中是不能有注释的。
不合法的
JSON
会在解析成JavaScript
对象时,出现错误。
#JSON和JavaScript对象的转化
#window.JSON
JSON
作为一种数据交换格式,被写入了ECMAScript 5,在IE8及之后的浏览器都提供了一个JSON
对象,用于对JSON
进行解析和序列化。
#JSON.parse()
此方法接收一个JSON
字符串,返回解析后的JavaScript对象,通常为Object
或Array
。
// JSON数据
var humansData = '[{"name":"zs","age":28},{"name":"ls","age":26}]';
// 解析为JavaScript对象
var humans = JSON.parse(humansData);
// 之后就可以访问其元素或属性了
humans[1].name; // ls
humans[1].age; // 26
如果传入不合法的
JSON
,则会在JSON.parse
时报错。
为什么我们在ajax请求中,即使请求的数据为JSON
,我们不用解析就能直接使用呢?
// test.text内容
/*
[{
"name":"zs",
"age":28
},{
"name":"ls",
"age":26
}]
*/
$.ajax({
url: './test/test.text',
dataType: 'JSON'
}).done(function(data){
console.dir(data); // Array[2]
console.log(data[0].name); // zs
// 这里没有转化为js对象就能访问其属性?!
});
这里实际是因为指定了dataType
为JSON,从而进行了自动转化,所以能直接在成功回调中使用其属性。如果去掉dataType
的指定,就不能直接访问其属性了,因为未转化时,其本身是一个字符串。第一行输出为test.text的内容,第二行输出undefined
。
#JSON.stringify()
此方法可接收一个JavaScript
值将转化为JSON
字符串,此字符串可被JSON.parse
还原。
var humans = [{
"name": "zs",
"age": 28,
"birth": new Date()
}, {
"name": "ls",
"age": 26,
"birth": new Date()
}];
// 转化为JSON字符串
JSON.stringify(humans);
// "[{"name":"zs","age":28,"birth":"2016-10-25T07:24:11.701Z"},{"name":"ls","age":26,"birth":"2016-10-25T07:24:11.701Z"}]"
前面我们讲到了JSON
中并非支持所有的JavaScript
类型,因此此方法对一些JSON
不可接受的值有所处理:原始对象中,如果有一个成员的值是undefined、函数或XML对象,这个成员会被省略。如果数组的成员是undefined、函数或XML对象,则这些值被转成null。
我们还发现,JSON
中是不支持Date
对象的,而上述转化为字符串的结果中正确包含了birth
的值,其为一个日期格式的字符串。这是因为在Date
对象上有一个名为toJSON
的方法,JSON.stringify
在序列化时,实际是调用了这个方法来输出结果的。
如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为:不是那个对象被序列化,而是调用 toJSON 方法后的返回值会被序列化,例如:
var obj = {
foo: 'foo',
toJSON: function() {
return 'bar';
}
};
JSON.stringify(obj); // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'
了解即可,详见: MDN:JSON.stringify(){.doc-link}
我们可能经常看到的是JSON.stringify( obj , null , 4)
,这样是什么意思呢?
对于上例,替换最后一句,结果如下所示:
JSON.stringify(humans, null, 4);
// "[
// {
// "name": "zs",
// "age": 28,
// "birth": "2016-10-25T07:24:11.701Z"
// },
// {
// "name": "ls",
// "age": 26,
// "birth": "2016-10-25T07:24:11.701Z"
// }
// ]"
其实没什么变化,不过是加上了空格缩进,使得可读性更高了。
其余两个参数的说明如下:
第二个参数可指定序列化时的操作。
如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;
如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;
如果该参数为null或者未提供,则对象所有的属性都会被序列化;
第三个参数用于指定缩进用的空白字符串,用于美化输出(pretty-print);
如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;
如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;
如果该参数没有提供(或者为null)将没有空格。
#替代方法
window.JSON
对象下虽然提供了完整的JSON
字符串和JavaScript
对象的转换方法。但是在IE8(兼容模式)以及更低版本的IE下没有提供这个对象,因此我们需要一些替代方案。
jQuery中提供了
parseJSON
这样一个方法来替代JSON.parse
,它接收一个标准格式的JSON
字符串,返回一个解析后的JavaScript
对象。使用http://www.json.org/提供了一个json.js,这样ie8(兼容模式),ie7和ie6就可以支持JSON对象以及其
stringify()
和parse()
方法; 可以在https://github.com/douglascrockford/JSON-js上获取到这个js,一般现在用json2.js。还可以使用
eval('(' + jsonstr + ')')
; 来将json字符串转换成json对象,注意需要在json字符外包裹一对小括号。但最好不要使用这种方式,因为这种方式不安全,eval
会将JSON
字符串作为JavaScript
语句来执行,JSON
中的风险代码将被执行。