一、什么是JSON?
1.1、JSON是一种数据交换格式
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
1.2、JSON独立于编程语言
JSON全称是JavaScript对象表示法,这个名字可能会让人误以为学习JSON需要先学习JavaScript。其实不然,数据交换格式是独立于语言的。
1.3、与XML相比,为何使用JSON?
对于 AJAX 应用程序来说,JSON 比 XML 更快更易使用:
使用 XML:
- 读取 XML 文档
- 使用 XML DOM 来循环遍历文档
- 读取值并存储在变量中
使用 JSON:
- 读取 JSON 字符串
- 用 eval() 处理 JSON 字符串
二、JSON语法
2.1、JSON 语法规则
- 数据在名称/值对中
- 两两数据之间用逗号分隔
- 大括号保存对象
- 中括号保存数组
正确的JSON语法中名称必须用双引号引起来。不过,不同于名称,值不总是需要被双引号包裹。当值是字符串是,必须使用双引号。
JSON的双引号:
不能通过验证的JSON:
{
title:"This is my title.",
body:"This is the body."
}
很显然这个JSON中名称没有用双引号包裹起来。但是有的人说我明明见过这种样子的数据呀!事实上,如果名称没有用双引号包裹起来那么它就不是JSON数据而是一个JavaScript对象
由于JavaScript的影响我们还能看见单引号包裹的名称和值,那也是JavaScript对象。
2.2、JSON 语法验证
在实际开发过程中我们使用JSON时可能会出现各种各样的错误(粗心造成的),所有我们要验证我们写的JSON是否正确。下面介绍几款JSON验证工具:
- JSON Editor Online:http://www.jsoneditoronline.cn/
- JSONLint:https://jsonlint.com/
三、JSON的数据类型
3.1、JSON 的数字类型
JSON中的数字可以是整数、小数、负数或者指数。
{
"money":29,
"price":129.90,
"earn":-100,
"earthMass":5.97219e+24
}
3.2、JSON 的对象数据类型
JSON中的对象类型非常简单。JSON本身就是对象,也就是一个被花括号包裹的名称-值对的列表。
{
"person":{
"name":"Tom",
"age":18,
"head":{
"hair":{
"color":"red",
"length":"long",
"style":"line"
},
"eyes":"green"
}
}
}
3.3、JSON 的字符串类型
除了提醒字符串类型必须用双引号包裹起来还需要注意的是字符串中直接包含双引号(或者其他特殊字符)是错误的。我们需要进行转义操作。
错误写法:
{
"sentence":"say "hello world""
}
正确写法:
{
"sentence":"say \"hello world\""
}
…………………………………………………………………………………………………………
错误写法:
{
"location":"C:\JSON"
}
正确写法:
{
"location":"C:\\JSON"
}
3.4、JSON 的布尔类型
在一些编程语言中,true可以用1表示,false可以用0表示。有时候true可以用大写TRUE表示,false一样。但是,在JSON中布尔类型只能用true和false表示,只能是小写形式,其他任何形式都会出错。
{
"football":true;
"swim":false
}
3.5、JSON 的null类型
对于一无所有的东西你可能会用0表示,但是0是一个数字,这本质上还是在计数。我们用null表示不存在的东西。而且null必须用小写表示。
3.6、JSON 的数组类型
JSON中的数组用[ ]包裹。在数组中没一项之间用”,”分隔开来。JSON数组中的值可以是任何合法的JSON数据类型。
{
"array": [
"test",
12,
100,
[
"array",
18
],
{
"color": "green"
},
null,
false
]
}
四、JSON Schema
不同于前面提及的语法验证,JSON Schema主要用于一致性验证。
我们使用JSON Schema验证下面问题:
- 值的数据类型是否正确?
- 我们可以具体规定值是数字或者字符串等其他类型。而不会出现我需要数字得到的确实字符串这种问题。
- 是否包含所需要的数据?
- 可以具体规定哪些数据是需要的,哪些是多余的。
- 值的形式是不是我需要的?
- 可以指定值的范围、最小值和最大值。
JSON Schema使用JSON来书写,仅仅需要几步我们就能掌握它。
1、在JSON第一个名称-值对中,声明其为一个schema文件:
{
"$schema": "http://json-schema.org/draft-06/schema#"
}
2、第二个名称-值对应该是JSON Schema文件的标题:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"title":"Cat"
}
3、第三个名称-值对要定义需要在JSON中包含的属性,名称为properties,他的值实质上是我们想要的JSON的骨架:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"title":"Person",
"properties":{
"name":{
"type":"string"
},
"age":{
"type":"number"
},
"good":{
"type":"boolean"
}
}
}
现在我们可以使用上面的Schema判断下面的JSON是合法的:
{
"name":"jack",
"age":21,
"good":true
}
我们已经解决了第一个问题。
对于数据,总有一些字段是必须要有的,某些是可有可无的,我们可以在Schema中使用“required”:
它的值是一个数组,数组中填入你想设置为必须输入的字段名
{
"$schema": "http://json-schema.org/draft-06/schema#",
"title":"Person",
"properties":{
"name":{
"type":"string"
},
"age":{
"type":"number"
},
"good":{
"type":"boolean"
}
},
"required":[
"name",
"age"
]
}
required字段加入之后JSON中必须包含name和age,否则就是不合法的JSON。
现在我们解决了第二个问题。
接下来我们需要解决第三个问题。比如人的年龄只能是大于0,并且有个合理的限制,我们可以设置JSON中age的范围。我们也可以设置字符串的长度。
{
"$schema": "http://json-schema.org/draft-06/schema#",
"title":"Person",
"properties":{
"name":{
"type":"string",
"minLength":3,
"maxLengtf":10
},
"age":{
"type":"number",
"minimum":0,
"maximum":100
},
"good":{
"type":"boolean"
}
},
"required":[
"name",
"age"
]
}
JSON Schema在线验证好帮手:
- JSON Schema Lint:https://jsonschemalint.com/#/version/draft-06/markup/json
- JSON Schema Validator:https://www.jsonschemavalidator.net/
五、JSON.parse()
JSON 通常用于与服务端交换数据。
在接收服务器数据时一般是字符串。
我们可以使用 JSON.parse() 方法将数据转换为 JavaScript 对象。
语法:
JSON.parse(text[, reviver])
参数说明:
- text:必需, 一个有效的 JSON 字符串。
- reviver: 可选,一个转换结果的函数, 将为对象的每个成员调用此函数。
通过JSON数据创建JavaScript对象:
注意:要确保JSON数据是正确的,否则解析出错。
<p id="demo"></p>
<script>
var obj = JSON.parse('{ "name":"Jack", "age":23, "addr":"xian" }');
document.getElementById("demo").innerHTML = obj.name + ":" + obj.addr;
</script>
从服务端接收 JSON 数据:
使用 AJAX 从服务器请求 JSON 数据,并解析为 JavaScript 对象。
<h2>使用 AJAX 来获取文件内容</h2>
<p>文件内容是标准的 JSON 格式,可以使用 JSON.parse 方法将其转换为 JavaScript 对象。</p>
<p id="demo"></p>
<script>
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myObj = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = myObj.name+":"+myObj.age;
}
};
xmlhttp.open("GET", "/JSON/demo.txt", true);
xmlhttp.send();
</script>
解析日期:
JSON 不能存储 Date 对象。
如果你需要存储 Date 对象,需要将其转换为字符串。
之后再将字符串转换为 Date 对象。
<p id="demo"></p>
<script>
var text = '{ "name":"Jack", "birthday":"1995-12-14", "addr":"xian"}';
var obj = JSON.parse(text);
obj.birthday = new Date(obj.birthday);
document.getElementById("demo").innerHTML = obj.name + "出生日期: " + obj.birthday;
</script>
使用第二个参数:
<p id="demo"></p>
<script>
var text = '{ "name":"Jack", "birthday":"1995-12-14", "addr":"xian"}';
var obj = JSON.parse(text, function (key, value) {
if (key == "birthday") {
return new Date(value);
} else {
if(key=="addr"){
return value+" city"
}else{
return value;
}
}});
document.getElementById("demo").innerHTML = obj.name + "出生日期: " + obj.birthday+"地址:"+obj.addr;
</script>
解析函数:
JSON 不允许包含函数,但你可以将函数作为字符串存储,之后再将字符串转换为函数。
<p id="demo"></p>
<script>
var text = '{ "name":"Jack", "fun":"function (a,b) {return a+b;}", "addr":"xian"}';
var obj = JSON.parse(text);
obj.fun = eval("(" + obj.fun + ")");<!--一定不能忘记加()-->
document.getElementById("demo").innerHTML = obj.name + " 调用函数:" + obj.fun(5,2);
</script>
不建议在 JSON 中使用函数。
六、JSON.stringify()
JSON 通常用于与服务端交换数据。
在向服务器发送数据时一般是字符串。
我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。
语法:
JSON.stringify(value[, replacer[, space]])
参数说明:
- value:
必需, 一个有效的 JSON 字符串。 - replacer:
可选,用于转换结果的函数或数组。
如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。使用返回值而不是原始值。如果此函数返回 undefined,则排除成员。根对象的键是一个空字符串:”“。
如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。当 value 参数也为数组时,将忽略 replacer 数组。 - space:
可选,文本添加缩进、空格和换行符,如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 space 大于 10,则文本缩进 10 个空格。space 有可以使用非数字,如:\t。
JavaScript 对象转换:
JSON.stringify() 方法处理JavaScript对象,将其转换为字符串:
<p id="demo"></p>
<script>
var obj = { "name":"jack", "age":23, "addr":"xian"};
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
</script>
JavaScript 数组转换:
将 JavaScript 数组转换为 JSON 字符串:
<p id="demo"></p>
<script>
var arr = [ "jack", "lucy", "tom", "john" ];
var myJSON = JSON.stringify(arr);
document.getElementById("demo").innerHTML = myJSON;
</script>
解析日期
JSON 不能存储 Date 对象。
JSON.stringify() 会将所有日期转换为字符串。
<p id="demo"></p>
<script>
var obj = { "name":"Jack", "birthday":new Date("1995-12-14"), "addr":"xian"};
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
</script>
解析函数
JSON 不允许包含函数,JSON.stringify() 会删除 JavaScript 对象的函数,包括 key 和 value。
<p id="demo"></p>
<script>
var obj = { "name":"Jack","fun":function(a,b){return a*b;}};
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
</script>
我们可以在执行 JSON.stringify() 函数前将函数转换为字符串来避免以上问题的发生:
<p id="demo"></p>
<script>
var obj = { "name":"Jack","fun":function(a,b){return a*b;}};
obj.fun = obj.fun.toString();
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
</script>
七、JSONP
Jsonp(JSON with Padding) 是 json 的一种”使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为同源策略。所谓同源是指,域名,协议,端口相同。所谓“同源策略“,简单的说就是基于安全考虑,当前域不能访问其他域的东西。
JSONP实现跨域请求的原理简单的说,就是动态创建<script>标签,然后利用<script>的src 不受同源策略约束来跨域获取数据。
JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=restful&count=1&callback=callbackFun";
document.body.insertBefore(script, document.body.firstChild);
返回的JSON作为参数传入回调函数中,我们通过回调函数来来操作数据:
function callbackFun(response){
console.log(response);
}
jQuery封装JSONP
jQuery封装的$.ajax中有一个dataType属性,如果将该属性设置成dataType:”jsonp”,就能实现JSONP跨域了。需要了解的一点是,虽然jQuery将JSONP封装在$.ajax中,但是其本质与$.ajax不一样。
实现代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery实现JSONP</title>
</head>
<body>
<div id="mydiv">
<button id="btn">Click</button>
</div>
</body>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
$.ajax({
async : true,
url : "https://api.douban.com/v2/book/search",
type : "GET",
dataType : "jsonp", // 返回的数据类型,设置为JSONP方式
jsonp : 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback
jsonpCallback: 'handleResponse', //设置回调函数名
data : {
q : "restful",
count : 2
},
success: function(response, status, xhr){
console.log('状态为:' + status + ',状态是:' + xhr.statusText);
console.log(response);
}
});
});
});
</script>
</html>
利用$.getjson()实现JSONP:
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script type="text/javascript">
$.getJSON("https://api.douban.com/v2/book/search?q=python&count=1&callback=?", function(data){
console.log(data);
});
</script>