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; // lshumans[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"}'
了解即可,详见: {.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
对象。使用提供了一个json.js,这样ie8(兼容模式),ie7和ie6就可以支持JSON对象以及其
stringify()
和parse()
方法; 可以在上获取到这个js,一般现在用json2.js。还可以使用
eval('(' + jsonstr + ')')
; 来将json字符串转换成json对象,注意需要在json字符外包裹一对小括号。但最好不要使用这种方式,因为这种方式不安全,eval
会将JSON
字符串作为JavaScript
语句来执行,JSON
中的风险代码将被执行。