最近学习并使用Vue的过程中,在使用Vue-resource的过程中遇到了以下问题:通过该插件异步请求数据的时候发现数据已经能正确请求到,但是无法通过response.json()解析返回体的body。通过查阅源码,发现该函数的主要作用就是将response对象中的body通过JSON.parse(this.body)解析为json对象。至于为什么会出现解析错误的情况,是因为自己写的json格式出现了错误,因此对json对象做了如下的总结。

JSON格式

1. 什么是json

json(Javascript Object Notation)是一种用于数据交换的文本格式。2001年由Douglas Crockford提出,目的是取代繁琐笨重的XML格式。

2. json格式与xml的比较

与同样作为数据传输的格式的xml比起来,json具有以下优点:

  • 书写简单,结构清晰,轻量级
  • 符合javascript的原生语法,解释器引擎可以直接处理

3. 对于json格式的几个规定:

  • 数组或对象的值可以是简单值也可以是复合值
  • 简单值包括:字符串、数值(必须是十进制标识)、布尔值和Null,其中(NaN,Infinity,-Infinity和undefined都会被转换为null)
  • 复合值包括符合json格式的数组或对象
  • 数组或对象的最后一个成员后面不能加逗号
  • 数组或对象之中的字符串必须使用双引号,不能使用单引号
  • 对象的成员名称必须使用双引号

注意:空数组或者空对象都是合格的json值,Null也是一个合格的json值
正确的json格式,例如:

1
2
3
4
5
6
7
["one", "two", "three"] //数组

{ "one": 1, "two": 2, "three": 3 }//对象,注意成员名称必须用双引号

{"names": ["张三", "李四"] }//值为复合对象

[ { "name": "张三"}, {"name": "李四"} ]//对象数组

json对象

ES5中添加了json对象,其包含两个方法:JSON.stringify()和JSON.parse()

1. JSON.stringify()
用处:将一个值转换为json格式的字符串,该字符串可以被JSON.parse()解析,需要注意以下几点:

  • 原始类型的字符串解析后会自动加上双引号
  • 原始对象中如有一个成员是undefined,函数或者是xml对象,则这个成员被忽略
  • 原始对象中如果数组的成员的是undefined,函数或者是xml对象,则被转换为null
  • 正则表达式会被转换为空对象
  • 自动忽略原始对象中不可遍历的属性
  • 可以接受一个数组参数,指定需要转换成字符串的属性
  • 可以接受一个函数作为参数,指定如何来转换成字符串,注意该函数是递归处理所有的键
  • 如何被转换的对象中包含一个toJSON方法,则会使用该方法的返回值,将该返回值转换为字符串,忽略其他成员(可以被用来处理转换正则表达式的情况)

2. JSON.parse()
用处:用来将json格式的字符串转换为对象。如果该json字符串不符合json格式,则会报错。

3. 示例

1
2
3
4
5
6
7
8
9
10
11
12
13

console.log(JSON.stringify('abc'));//""abc""字符串默认加上双引号
console.log(JSON.stringify(1));//"1"
console.log(JSON.stringify(false) );//"false"
console.log(JSON.stringify([]));//"[]"
console.log(JSON.stringify({}));//"{}"
console.log(JSON.stringify([1, "false", false]));//"[1, "false", false]"
console.log(JSON.stringify({ name: "张三" }));//"{"name":"张三"}" 成员名称双引号
console.log(JSON.stringify({
f: function(){},
a: [ function(){}, undefined ]
}));//"{"a":[null,null]}"
console.log(JSON.stringify(/foo/));//"{}"正则表达式会被转换为空对象

以上代码中需要注意:

  • 关于字符串的转换需要加双引号
  • 成员名要加双引号
  • 对于被转换对象中某个成员是函数、undefined、xml对象直接忽略。这三种情况在数组中出现时被转换为null
  • 正则表达式会被转换为空对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14

var obj = {};
Object.defineProperties(obj, {
'foo': {
value: 1,
enumerable: true
},
'bar': {
value: 2,
enumerable: false
}
});

console.log(JSON.stringify(obj)); // {"foo":1}

以上代码中需要注意:JSON.stringify只能转换对象中可遍历的属性,不可遍历的属性自动忽略

1
2
3
4
5
6
7
8
9
var obj = {
'prop1': 'value1',
'prop2': 'value2',
'prop3': 'value3'
};

var selectedProperties = ['prop1', 'prop2'];

console.log(JSON.stringify(obj, selectedProperties));// "{"prop1":"value1","prop2":"value2"}"

以上代码中需要注意:可以给JSON.stringify指定额外一个数组参数,用来指定将对象中哪些属性转换为字符串

1
2
3
4
5
6
7
8
9
function change(key, value) {
if (typeof value === "number") {
value = 2 * value;
}
return value;
}

console.log(JSON.stringify({ a: 1, b: 2 }, change));
// '{"a": 2,"b": 4}'

以上代码中需要注意的是:可以给JSON.stringify指定一个函数参数,用来改变转换字符串过程中的行为

1
2
3
4
5
6
7
8
9
10
11
12
var o = {a: {b: 1}};

function f(key, value) {
console.log("["+ key +"]:" + value);
return value;
}

console.log(JSON.stringify(o, f));
// []:[object Object]
// [a]:[object Object]
// [b]:1
// '{"a":{"b":1}}'

以上代码说明了如果指定JSON.stringify的函数参数,处理函数是递归的处理每一个键值对。因此看下一个例子:

1
2
3
4
5
6
7
8
9
10
11
var o = {a: 1};

function change(key, value){
if (typeof value === "object"){
return {b: 2};
}
return value * 2;
}

console.log(JSON.stringify(o,change));
// "{"b": 4}"

在上面的代码中形象的体现了这一点,函数是递归来处理的。首先第一次递归,将该对象转换成了{b: 2},然后接下里的递归中根据该改变后的对象值进行递归,因此打印出来的是{b:4}

1
2
3
4
5
6
7
8
9
function f(key, value) {
if (typeof(value) == "string") {
return undefined;
}
return value;
}

console.log(JSON.stringify({ a:"abc", b:123 }, f));
// '{"b": 123}'

以上代码中需要注意的是:如果处理函数中返回了undefined或者没有返回值,则该属性被忽略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log(JSON.stringify({ p1: 1, p2: 2 }, null, 2));
/*
"{
"p1": 1,
"p2": 2
}"
*/


console.log(JSON.stringify({ p1:1, p2:2 }, null, "|-"));
/*
"{
|-"p1": 1,
|-"p2": 2
}"
*/

以上代码中需要注意的是:可以给JSON.stringify()指定第三个参数,用来格式化输出的字符串。如果是数字,则表示每个属性前面添加的空格,如果是字符串,则加在每行输出的前面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log(JSON.stringify({
toJSON: function() {
return "Cool"
}
}));
// "Cool""

var o = {
foo: 'foo',
toJSON: function() {
return 'bar';
}
};
console.log(JSON.stringify({x: o}));
// '{"x":"bar"}'

以上代码中需要注意的是:如果被转换的对象中含有toJSON方法,则使用toJSON的返回值进行转换,其他属性忽略。

1
2
3
4
RegExp.prototype.toJSON = RegExp.prototype.toString;

console.log(JSON.stringify(/foo/));
// "/foo/"

以上代码就是toJSON的一个应用,用来对正则表达式应用JSON.stringify。


该篇对于json的学习主要来源于阮一峰老师的教程。
参考文章:JavaScript 标准参考教程(alpha)