前面的话
json(javascript object notation) 全称是 javascript 对象表示法,它是一种数据交换的文本格式,而不是一种编程语言,用于读取结构化数据。2001 年由 Douglas Crockford 提出,目的是取代繁琐笨重的 XML 格式。本文将详细介绍关于 json 的内容
语法规则
JSON 的语法可以表示以下三种类型的值
【1】简单值
简单值使用与 JavaScript 相同的语法,可以在 JSON 中表示字符串、数值、布尔值和 null
字符串必须使用双引号表示,不能使用单引号。数值必须以十进制表示,且不能使用 NaN 和 Infinity
[注意]JSON 不支持 JavaScript 中的特殊值 undefined
- //合格的简单值
- 5 "hello world"true null
- //不合格的简单值
- + 0x1 'hello world'undefined NaN Infinity
【2】对象
对象作为一种复杂数据类型,表示的是一组有序的键值对儿。而每个键值对儿中的值可以是简单值,也可以是复杂数据类型的值
与 javascript 的对象字面量相比,json 有三个不同的地方
1、JSON 没有变量的概念
2、JSON 中,对象的键名必须放在双引号里面
3、因为 JSON 不是 javascript 语句,所以没有末尾的分号
[注意] 同一个对象中不应该出现两个同名属性
- //合格的对象
- {
- "name": "huochai",
- "age": 29,
- "school": {
- "name": "diankeyuan",
- "location": "beijing"
- }
- }
- //不合格的对象
- {
- name: "张三",
- 'age': 32
- } //属性名必须使用双引号
- {}; //不需要末尾的分号
- {
- "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
- "getName": function() {
- return this.name;
- }
- } // 不能使用函数和日期对象
【3】数组
数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型——简单值、对象或数组
JSON 数组也没有变量和分号,把数组和对象结合起来,可以构成更复杂的数据集合
[注意] 数组或对象最后一个成员的后面,不能加逗号
JSON 对象
JSON 之所以流行,是因为可以把 JSON 数据结构解析为有用的 javascript 对象
ECMAScript5 对解析 JSON 的行为进行了规范,定义了全局对象 JSON
[注意]IE7 - 浏览器不支持
JSON 对象有两个方法:stringify() 和 parse()。这两个方法分别用于把 JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值
stringify()
JSON.stringify() 方法用于将一个值转为字符串。该字符串应该符合 JSON 格式,并且可以被 JSON.parse() 方法还原
默认情况下,JSON.stringify() 输出的 JSON 字符串不包括任何空格字符或缩进
- var jsonObj = {
- "title": "javascript",
- "group": {
- "name": "jia",
- "tel": 12345
- }
- };
- //{"title":"javascript","group":{"name":"jia","tel":12345}}
- JSON.stringify(jsonObj);
具体转换
- JSON.stringify('abc') // ""abc""
- JSON.stringify(1) // "1"
- JSON.stringify(false) // "false"
- JSON.stringify([]) // "[]"
- JSON.stringify({}) // "{}"
- JSON.stringify([1, "false", false]) // '[1,"false",false]'
- JSON.stringify({
- name: "张三"
- }) // '{"name":"张三"}'
stringify() 方法把正则表达式和数学对象转换成空对象的字符串形式
- JSON.stringify(/foo/) // "{}"
- JSON.stringify(Math) // "{}"
stringify() 方法把日期对象和包装对象转换成字符串
- JSON.stringify(new Boolean(true)) //"true"
- JSON.stringify(new String('123')) //""123""
- JSON.stringify(new Number(1)) //"1"
- JSON.stringify(new Date()) //""2016-09-20T02:26:38.294Z""
如果对象的成员是 undefined 或函数,这个成员会被省略
如果数组的成员是 undefined 或函数,则这些值被转成 null
- JSON.stringify({
- a: function() {},
- b: undefined,
- c: [function() {},
- undefined]
- });
- // "{"c":[null,null]}"
JSON.stringify() 方法会忽略对象的不可遍历属性
- var obj = {};
- Object.defineProperties(obj, {
- 'foo': {
- value: 1,
- enumerable: true
- },
- 'bar': {
- value: 2,
- enumerable: false
- }
- });
- JSON.stringify(obj); // {"foo":1}]
参数
JSON.stringify() 除了要序列化的 JavaScript 对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化 JavaScript 对象。第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在 JSON 字符串中保留缩进
【数组过滤器】
当 stringify() 方法的第二个参数是一个数组时,这时相当于实现一个过滤器的功能
【1】过滤器只对对象的第一层属性有效
- var jsonObj = {
- "title": "javascript",
- "group": {
- "a": 1
- }
- };
- //{"group":{"a":1}}
- console.log(JSON.stringify(jsonObj, ["group", "a"]))
【2】过滤器对数组无效
- var jsonObj = [1, 2];
- JSON.stringify(jsonObj, ["0"]) //"[1,2]"
【函数参数】
stringify()方法的第二个参数也可以是一个函数。传入的函数接收两个参数,属性 (键) 名和属性值
- JSON.stringify({
- a: 1,
- b: 2
- },
- function(key, value) {
- if (typeof value === "number") {
- value = 2 * value;
- }
- return value;
- })
- // "{"a":2,"b":4}"
属性名只能是字符串,而在值并非键值对儿结构的值时,键名可以是空字符串
这个函数参数会递归处理所有的键
下面代码中,对象 o 一共会被 f 函数处理三次。第一次键名为空,键值是整个对象 o;第二次键名为 a,键值是 {b:1};第三次键名为 b,键值为 1
- JSON.stringify({
- a: {
- b: 1
- }
- },
- function(key, value) {
- console.log("[" + key + "]:" + value);
- return value;
- })
- // []:[object Object]
- // [a]:[object Object]
- // [b]:1
- // '{"a":{"b":1}}'
函数返回的值就是相应键的值。如果函数返回了 undefined 或没有返回值,那么相应的属性会被忽略
- JSON.stringify({
- a: "abc",
- b: 123
- },
- function(key, value) {
- if (typeof(value) === "string") {
- return undefined;
- }
- return value;
- })
- // '{"b": 123}'
【缩进】
stringify() 方法还可以接受第三个参数,用于增加返回的 JSON 字符串的可读性
如果是数字,表示每个属性前面添加的空格 (最多不超过 10 个)
如果是字符串 (不超过 10 个字符),则该字符串会添加在每行前面
- /*"{
- "p1": 1,
- "p2": 2
- }"*/
- JSON.stringify({
- p1: 1,
- p2: 2
- },
- null, 2);
- //"{"p1":1,"p2":2}"
- JSON.stringify({
- p1: 1,
- p2: 2
- },
- null, 0);
- /*"{
- |-"p1": 1,
- |-"p2": 2
- }"*/
- JSON.stringify({
- p1: 1,
- p2: 2
- },
- null, '|-');
- toJSON()
有时候,JSON.stringify() 还是不能满足对某些对象进行自定义序列化的需求。在这些情况下, 可以通过对象上调用 toJSON() 方法,返回其自身的 JSON 数据格式
- JSON.stringify({
- toJSON: function() {
- return "Cool"
- }
- })
- // ""Cool""
- var o = {
- foo: 'foo',
- toJSON: function() {
- return 'bar';
- }
- };
- JSON.stringify({
- x: o
- }); // '{"x":"bar"}'
如果 toJSON() 方法返回 undefined,此时如果包含它的对象嵌入在另一个对象中,会导致该对象的值变成 null。而如果包含它的对象是顶级对象,结果就是 undefined
- JSON.stringify({
- toJSON: function() {
- return undefined
- }
- })
- //undefined
Date 对象部署了一个自己的 toJSON 方法,自动将 Date 对象转换成日期字符串
- JSON.stringify(new Date("2016-08-29"))
- // "2016-08-29T00:00:00.000Z"
toJSON 方法的一个应用是,可以将正则对象自动转为字符串
- RegExp.prototype.toJSON = RegExp.prototype.toString;
- JSON.stringify(/foo/) // ""/foo/""
toJSON() 可以作为函数过滤器的补充,因此理解序列化的内部顺序十分重要。假设把一个对象传入 JSON.stringify(),序列化该对象的顺序如下
1、如果存在 toJSON() 方法而且能通过它取得有效的值,则调用该方法。否则,按默认顺序执行序列化
2、如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第一步返回的值
3、对第二步返回的每个值进行相应的序列化
4、如果提供了第三个参数,执行相应的格式化
parse()
JSON.parse 方法用于将 JSON 字符串转化成对象
- JSON.parse('{}') // {}
- JSON.parse('true') // true
- JSON.parse('"foo"') // "foo"
- JSON.parse('[1, 5, "false"]') // [1, 5, "false"]
- JSON.parse('null') // null
- var o = JSON.parse('{"name": "张三"}');
- o.name // 张三
如果传入的字符串不是有效的 JSON 格式,JSON.parse 方法将报错
//Uncaught SyntaxError: Unexpected token u in JSON at position 0(…)
JSON.parse("'String'")
//Uncaught SyntaxError: Unexpected token u in JSON at position 0(…)
JSON.parse("undefined")
JSON.parse() 方法也可以接收一个函数参数,在每个键值对儿上调用,这个函数被称为还原函数 (reviver)。该函数接收两个参数,一个键和一个值,返回一个值
如果还原函数返回 undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入到结果中
- var o = JSON.parse('{"a":1,"b":2}',
- function(key, value) {
- if (key === '') {
- return value;
- }
- if (key === 'a') {
- return value + 10;
- }
- });
- o.a // 11
- o.b // undefinef
在将日期字符串转换为 Date 对象时,经常要用到还原函数
- var book = {
- "title": "javascript",
- "date": new Date(2016, 9, 1)
- }
- var jsonStr = JSON.stringify(book);
- //'{"title":"javascript","date":"2016-09-30T16:00:00.000Z"}''
- console.log(jsonStr) var bookCopy = JSON.parse(jsonStr,
- function(key, value) {
- if (key == 'date') {
- return new Date(value);
- }
- return value;
- }) console.log(bookCopy.date.getFullYear()); //2016
eval()
实际上,eval() 类似于 JSON.parse() 方法,可以将 json 字符串转换为 json 对象
- eval('(' + '{"a":1}' + ')').a; //1
- JSON.parse('{"a":1}').a; //1
但是,eval() 可以执行不符合 JSON 格式的代码,有可能会包含恶意代码
- eval('(' + '{"a":alert(1)}' + ')').a; //弹出1
- JSON.parse('{"a":alert(1)}').a; //报错
所以,还是要尽量少使用 eval()
来源: http://www.jb51.net/article/94974.htm