JSON可以直接传给eval()而不需要创建DOM。
把JSON当成一种数据格式,而不是编程语言。
JSON不属于JavaScript,它们只是拥有相同的语法而已。
JSON也不是只能在JavaScript中使用,它是一种通用数据格式,很多语言都有解析和序列化JSON的内置能力。
所有浏览器都已经原生支持全局JSON对象。
语法
JSON语法支持表示3种类型的值:
- 简单值:字符串、数值、布尔值和null可以在JSON中出现。特殊值undefined不可以。
- 对象:第一种复杂数据类型,对象表示有序键/值对。每个值可以是简单值,也可以是复杂类型。
- 数组:第二种复杂数据类型,数组的值可以是任意类型,包括简单值、对象,甚至其他数组。
JSON没有变量、函数或对象实例的概念,JSON的所有记号都只为表示结构化数据,只是借用了JS的语法,千万别与JS语言混淆。
简单值
JavaScript字符串与JSON字符串的主要区别是,JSON字符串必须使用双引号(单引号会导致语法错误)。
"Hello world!!" 布尔值和null本身也是有效的JSON值,不过在实践中,更多使用JSON表示比较复杂的数据结构,其中会包含简单值。
对象
JavaScript中的对象字面量:
let person = {
name : "CLN",
age : 21
};
而用JSON表示相同对象的语法是:
{
"name":"CLN",
"age":21
}
JSON中的对象必须使用双引号把属性名包围起来。JSON主要有两处不同,第一是没有声明变量(JSON中没有变量),第二是最后没有分号(此处不是JS语句,因此不需要)。
属性的值可以是简单值或复杂数据类型值,后者可以在对象中再嵌入对象,比如:
{
"name":"CLN",
"age":21,
"school":{
"name":"Nanqiang College",
"location" :"Taibei"
}
}
同一个对象不允许出现两个相同的属性。
数组
JavaScript数组:
let values = [21, "idol", true]; 在JSON中可以使用类似语法表示相同的数组: [21, "idol", true] 数组和对象可以组合使用,以表示更加复杂的数据结构,比如:
[
{
"title":"Learn about JavaScript",
"authors":[
"Nikcjoa Zakad",
"Matt Fsfds"
],
"year":2018
},
{
"title":"Learn about JavaWeb",
"authors":[
"John Huwdm"
],
"year":2019
}
]
解析与序列化
JSON的迅速流行,主要因为JSON可以直接被解析成可用的JavaScript对象。
JSON出现之后就迅速成为了Web服务的事实序列化标准。
JSON对象
JSON对象有两个方法:
stringify()
将JavaScript序列化为JSON字符串。 默认情况下,JSON.stringify()会输出不包含空格或缩进的JSON字符串。
parse()
将JSON解析为原生JavaScript值。 JSON字符串可以直接传给JSON.parse(),然后得到相应的JavaScript值。 若传入的JSON字符串无效,则会导致抛出错误。
序列化选项
JSON.stringify()方法除了要序列化的对象,还可以接收两个参数:
- 第一个参数是过滤器,可以是数组或函数;
- 第二个参数是用于缩进结果JSON字符串的选项。
- 过滤结果 若第二个参数是一个数组,则此方法返回的结果只包含数组中列出的对象属性。
let book = {
title : "Learn about JavaScript",
authors : [
"Nikcjoa Zakad",
"Matt Fsfds"
],
edition : 4,
year : 2019
};
let jsonText = JSON.stringify(book, ["title", "edition"]);
// JSON字符串结果
// { "title": "Learn about JavaScript", "edition" : 4 }
若第二个参数是一个函数,提供的函数接收两个参数:属性名(key)和属性值(value)。 这个key始终是字符串,只是在值不属于某个键/值对时回是空字符串。
返回的值就是相应key应包含的结果。返回undefined会导致属性被忽略。
let jsonText = JSON.stringify(book, (key, value) => {
switch(key){
case "authors" :
return value.join(",")
case "year" :
return 5000;
case "edition" :
return undefined;
default : // 一定要提供默认返回值,以便返回其他属性传入的值
return value;
}
});
第一次调用这个函数,实际上都会传入空字符串key,值是book对象,返回JSON字符串如下:
{ "title": "Learn about JavaScript","authors" : "Nikcjoa Zakad Matt Fsfds", "year" : 5000 }
- 字符串缩进 JSON.stringify()方法的第三个参数控制缩进和空格。 在这个参数为数值时,表示每一级缩进的空格数。
let jsonText = JSON.stringify(book, null, 4);
// 得到的结果如下
{
"title": "Learn about JavaScript",
"authors" : [
"Nikcjoa Zakad",
" Matt Fsfds"
]
"edition" : 4,
"year" : 5000
}
如果缩进参数是一个字符串而非数值,则JSON字符串就会使用这个字符串来缩进。 可以设置缩进字符为Tab或任意字符。
let jsonText = JSON.stringify(book, null, “--”);
// 得到的结果如下
{
--"title": "Learn about JavaScript",
--"authors" : [
----"Nikcjoa Zakad",
----" Matt Fsfds"
--]
--"edition" : 4,
--"year" : 5000
}
- toJSON()方法 有时,对象需要在JSON.stringify()之上自定义JSON序列化。 此时,可以在要序列化的对象中添加toJSON()方法,序列化时会基于这个方法返回适当的JSON表示。
let book = {
title : "Learn about JavaScript",
authors : [
"Nikcjoa Zakad",
"Matt Fsfds"
],
edition : 4,
year : 2019,
toJSON:function(){
return this.title;
}
};
let jsonText = JSON.stringify(book);
toJSON()方法可以返回任意序列化值。 如果对象被嵌入在另一个对象中,返回undefined会导致值变成null;或者如果是顶级对象,则本身就是undefined。
箭头函数不能用来定义toJSON()方法,因为箭头函数词法作用域是全局作用域,在这种情况下不合适。
toJSON()方法可以与过滤函数一起使用。
解析选项
JSON.parse()方法也可接收一个额外的参数,这个函数会针对每个键/值对都调用一次。为区别于传给JSON.stringify()的起过滤作用的替代函数,这个函数被称为还原函数。
如果还原函数返回undefined,则结果中就会删除相应的键。 如果返回了其他任何值,则该值会成为相应键的值插入到结果中。
还原函数经常被用于把日期字符串转换为Date对象。如:
let book = {
title : "Learn about JavaScript",
authors : [
"Nikcjoa Zakad",
"Matt Fsfds"
],
edition : 4,
year : 2019,
releaseDate:new Date(2017, 11, 1)
};
let jsonText = JSON.stringify(book);
let bookCopy = JSON.parse(jsonText,
(key, value) => key == "releaseDate" ? new Date(value) : value);
alert(bookCopy.releaseDate.getFullYear());