JSON
介绍
在 JSON
出现以前,XML
是互联网上传输结构化数据的标准,不过在 JSON
出现之后这种情况就改变了,这主要是因为 JSON
对比与 XML
有如下两个明显的优势 :
-
提取数据更加方便,如果你写过
Java
程序就会知道,当我们需要将数据从配置文件 (XML 格式) ,需要很长的一段代码,非常麻烦。 -
可以直接将
JSON
数据解析成JavaScript
对象。
很多编程语言都有 JSON
的解析器和序列化器,方便我们快速的将数据转换成 JSON
格式。
数据格式
JSON
语法可以表示三种类型的值 :
-
简单值 : 也就是数字和字符串之类的数据
-
对象
-
数组
下面看看 JSON
语法和 JavaScript
中的数据表示有何差异。
-
对于数值而言,其表达形式和其在
JavaScript
中相同,如下面这行代码在控制台打印结果就是5
。var result = JSON.stringify(5); console.log(result);
-
对于字符串,值得注意的一点是,在
JSON
语法中,字符串只能用双引号表示,不能用单引号(单引号会导致语法错误)。比如下面这行代码会报错。console.log(JSON.parse('Hello JSON!'));
-
对于对象,
JSON
语法和JavaScript
的表达有如下差异 :-
JSON
语法中没有变量的概念。 -
JSON
语法中对象的每个属性名都要加上双引号。 -
JSON
语法中不用加分号结束语句。
-
在 JavaScript
中,我们声明一个对象的形式如下所示:
var n = {
name: "hwaphon",
age: 18
};
将其转换成 JSON
格式,就变成了下面这种格式:
{"name":"hwaphon","age":18}
- 对于数组,
JSON
和JavaScript
用同样的表示方式!
使用
在 JavaScript
中,我们可以用 JSON.stringify()
方法将一个目标转换成 JSON
字符串。值得注意的是,在序列化 JavaScript
对象的时候,所有函数以及原型对象都会被忽略,不体现在结果中,那些属性值为 undefined
的也会被跳过。
其实一般的时候我们只能用到 JSON.stringify()
的第一个参数,也就是我们要序列化的对象,不过这个函数还有其它两个参数,一个是过滤器(可以是数组,也可以是函数), 另一个是选项,表示是否需要保留原字符串的缩进。
下面先来看看第二个参数,以下面这个对象为例:
var Person = {
name: "hwaphon",
sex: "man",
age: 21,
address: "Anhui"
};
先传入一个数组来看看:
console.log(JSON.stringify(Person, ["name", "address"]));
运行结果为
{"name":"hwaphon","address":"Anhui"}
可见,返回的结果中只包含了在数组中指定的属性,其它的属性都一概被省略了。
如果传入一个函数,那情况就又有不同了,首先,我们需要这个函数会自带两个参数,也即是 key
和 value
, 很容易猜出其实 key
对应的也就是属性名,而 value
对应的是属性值。这样的话,我们就可以在序列化数据的时候对数据做进一步的处理。
var result = JSON.stringify(Person, function(key, value){
switch(key) {
case "name":
return "Hello," + value;
case "age":
return "Secret";
default:
return value;
}
});
在上面的代码中,当处理姓名时,加了一个 Hello
字符串,处理年龄时,将年龄改成了 Secret
, 对于其他值则照常返回其值。所以,现在你不难猜出 result
的值。
{"name":"Hello,hwaphon","sex":"man","age":"Secret","address":"Anhui"}
如果你想省略某个值,很简单,在 case
语句中直接 return undefined
即可。
第三个参数用于表示字符串的缩进,比如我们将代码携程如下格式:
var result = JSON.stringify(Person, ["name", "age"], 4);
console.log(result);
那么输出将变成:
{
"name": "hwaphon",
"age": 21
}
也就是说,在每行属性中插入了四个空格,你可以将这个值设置为 [0, 10]
区间内的任何一个数,如果你设置了一个超过 10 的数,那么其默认为 10,如果你将这个参数写成了一个字符串,比如 *
,那么其输出将会是下面这种格式:
{
*"name": "hwaphon",
*"age": 21
}
还有一点值得提及,其实在每个对象中,我们都可以写一个 toJSON()
方法,这样的话当序列化时会默认执行这个函数,如果又提供了 toJSON()
函数,又在 JSON.stringify()
中指定了第二个参数 , 那么默认会先执行 toJSON()
, 根据这个函数的返回结果再应用第二个参数对数据进行过滤。
好了,介绍完了序列化方法,下面来看看如何将一个 JSON
字符串解析出来,这需要借助于 JSON.parse()
方法。这个方法有两个参数,第一个参数是要解析的字符串,第二个参数是一个过滤器,和 stringify()
中的第二个参数是对应的。比如对于一个人的性别,我们想让其在 JavaScript
中显示为 man
和 woman
, 而在 JSON
字符串中分别显示为 1 和 2.
var Person = {
name: "hwaphon",
sex: "man"
};
var result = JSON.stringify(Person, function(key,value){
if(key === "sex") {
if(value === "man") {
return 1;
} else {
return 2;
}
} else {
return value;
}
});
var newPerson = JSON.parse(result, function(key, value){
if(key === "sex") {
if(value === 1) {
return "man";
} else {
return "woman";
}
} else {
return value;
}
});
利用 JSON 实现深克隆
之前说过,在序列化对象的时候,所有对象以及原型都会被忽略,所以我们可以利用这一特点来实现深克隆,其实非常简单,只用一行代码就可以完成。
var newObject = JSON.parse(JSON.stringify(oldObject));
需要注意的是,虽然函数,对象以及原型不在 JSON
返回的结果中,不过当你解析对象的时候,这些属性仍然存在,而且是和原对象相同但不相等。
提示: 可以利用 Object.assign()
方法来实现浅克隆。