一种结构化数据的格式,与JavaScript有相同的语法形式,但不属于JavaScript。支持多种编程语言。
1、语法
JSON有3种类型的值:简单值、对象 和 数组。
简单值:字符串、数值、布尔值、null (JSON不支持JavaScript的特殊值undefined)
对象:一组无序键值对。值可为简单值,或对象和数组。
数组:一组有序键值对。值可为简单值,或对象和数组
JSON不支持变量、函数 和 对象实例。
1-1、简单型
JSON字符串必须使用双引号(单引号会导致语法错误)
1-2、对象
JSON对象的属性必须使用双引号:
{ "name":"xiaoming", "age":24
}
与JavaScript对象字面量的区别:无声明变量;无末尾分号。
1-3、数组
同样无声明对象;无末尾分号。
2、解析 与 序列化
2-1、JSON对象
早期JSON解析器使用JavaScript的eval()函数解析、解释 并 返回JavaScript对象和数组。ECMAScript5定义了全局对象JSON(支持IE8+ 等 主流浏览器)。
eval()对JSON数据结构求值存在风险,可能会执行恶意代码,故早期浏览器可使用shim:https://github.com/douglascrockford/JSON-js
JSON对象的两个方法:stringify()、parse()
stringify():将JavaScript对象 序列化 为JSON字符串。
stringify()
JSON.stringify()输出的JSON字符串 默认 不包含缩进、空格符 和 换行符。
序列化JavaScript对象时,所有函数、原型成员 和 值为undefined的属性 都会被忽略。
parse():将JSON字符串 解析 为原生JavaScript值
传给JSON.parse()的字符串不是有效JSON时,会抛出错误。
※即使stringify()之前和parse()后 两个对象属性相同,也是两个完全独立的对象。
2-2、序列化
JSON.stringify()有3个参数:JavaScript对象、过滤器、控制缩进等格式化
1-过滤器(过滤结果):数组、函数
数组过滤器:JSON.stringify()的结果 将只包含数组中列出的 属性:
数组过滤器
函数过滤器:函数有2个参数,为属性(键)名 和 属性值。属性名只能为字符串,非键值对结构的键名 为空字符串。
通过函数处理特定的属性。序列化的对象中的每个对象都要进过过滤器。
函数过滤器
☆实际上,第一次调用函数过滤器时,传入的是一个空字符串,值为这个book对象
2-字符串缩进
JSON.stringify()的第3个参数 用于控制结果的缩进和空白符。(换行符会在传入有效缩进参数时,自动添加)
当为数值时,表示每级缩进的空格数;
当为非数值时,做为缩进字符(不再使用空格缩进)。
※最大缩进数和缩进字符为10,超过时自动转换为10
View Code
3-toJSON()方法
toJSON()方法 可用于返回任何值;也可作为过滤器的补充,进行根精确的自定义序列化需求。
例子
☆☆☆☆☆
☆ 将一个对象传入JSON.stringify()后 的序列化 顺序:
①若存在 而且 能通过toJSON()获取有效值,将先调用该方法。否则返回对象本身;
②若存在 第2参数,将①返回的值传入 过滤器;
③对②返回的每个值 进行相应的序列化;
④若存在 第3参数,对序列化后的数据 进行相应格式化。
2-3、解析
JSON.parse() 2个参数:JSON对象、函数(还原函数‘reviver’,与序列化的替换函数'replacer'具有相同签名:2个参数——键与值)
还原函数:若此函数返回undefined,将会删除相应的键,若返回其他值,则会被插入结果中。
JSON是一个轻量级的数据格式,可以简化表示数据结构的工作量。在实际工作中,我们经常用它来传递数据,不过对于其使用的一些细节还是需要注意的。在ECMAScript5中定义了原生的JSON对象,可以用来将对象序列化为JSON字符串,或者将JSON数据解析为javascript对象。
一、JSON语法
JSON可以用来表示三种类型的值:简单值、对象和数组。对象和数组一般是JSON结构的最外层形式。
1.JSON简单值
可以在JSON中表示字符串、数值、布尔值、null。
例如:
5//数值类型
"hello json"//字符串类型
注意:
①JSON不支持js中的特殊值undefined;
②JSON字符串必须使用双引号,不能使用单引号。
③在实际应用中,JSON一般用来表示较复杂的数据结构,而简单值一般用作复杂数据结构中的一部分。
2.对象
JSON对象与JavaScript对象字面量对象的语法是类似的。
//JavaScript对象字面量表示
var jsWeatherinfo={
city:"北京",
cityid:"101010100",
weather:"多云转晴"
//JSON对象
{
"city":"北京",
"cityid":"101010100",
"weather":"多云转晴"
}
但是有几点不同:
①JSON中没有变量的概念,所以没有声明变量;
②JSON末尾没有分号;
③JSON对象中的属性名一定要使用双引号,而JavaScript对象中的属性引号是可有可无的。
3.数组
JSON数组采用的是javascript的数组字面量形式.
//JavaScript数组
var result=[1,true,"today"];
//JSON数组
[1,true,"today"]
区别:JSON数组没有末尾的分号,也没有声明变量.
二、JSON序列化
1.JSON对象
JavaScript的eval()函数可以用来解析JSON并返回JavaScript对象,不过eval()对JSON结构求值是存在风险的.因此,在ECMAScript5中新增了全局的JSON对象.JSON对象有两个方法:stringify()和parse().
stringify()用于把JavaScript对象序列化为JSON字符串;
parse()用于把JSON字符串解析为原生的JavaScript值.
var weather={
'city': '北京',
'cityid': '101010100',
'temp1': '31℃',
'temp2': '20℃',
'weather': '多云转晴',
'img1': 'd1.gif',
'img2': 'n0.gif',
'ptime': '11:00'
};
var text=JSON.stringify(weather);
var json=JSON.parse(text);
json.weather;//"多云转晴"
2.JSON.stringify()
JSON.stringify()方法有三个参数:
第一个参数是要序列化的JavaScript对象;
第二个参数是过滤器,可以是一个数组或者函数;
第三个参数是一个布尔值,表示是否在JSON字符串中保留缩进.
①过滤器
如果过滤器参数是数组,那么stringify()结果中只包含该数组中列出的属性.
var weather={
'city': '北京',
'cityid': '101010100',
'temp1': '31℃',
'temp2': '20℃',
'weather': '多云转晴',
'img1': 'd1.gif',
'img2': 'n0.gif',
'ptime': '11:00'
};
var text=JSON.stringify(weather,["city","weather","temp1","temp2"]);
//结果:"{"city":"北京","weather":"多云转晴","temp1":"31℃","temp2":"20℃"}"
如果过滤器是函数,传入的函数有两个参数:属性名和属性值.根据属性名来判断如何处理序列化对象中相应的属性.如果函数返回了undefined,那么相应的属性就会被忽略.
var text1 = JSON.stringify(weather, function (key, value) {
switch (key) {
case 'temp1':
return '最高温度' + value;
case 'temp2':
return '最低温度' + value;
case 'img1':
case 'img2':
case 'ptime':
return undefined;//属性被忽略
default:
return value;
}
});
//结果:"{"city":"北京","cityid":"101010100","temp1":"最高温度31℃","temp2":"最低温度20℃","weather":"多云转晴"}"
③字符串缩进
JSON.stringify()第三个参数用来控制结果中的缩进情况.
如果缩进参数传入的是数值,表示每个json字段缩进的空格数,但是最大缩进空格数不超过10.
var text2=JSON.stringify(weather,null,5)
如果缩进参数传入的是字符串,则表示JSON字符串中每个级别都使用该字符串作为缩进字符.不过该字符串也不能超过10个字符长.
var text3=JSON.stringify(weather,null,"--")
④toJSON()方法
如果JSON.stringify()不能满足某些对象的序列化需求,可以给对象自定义toJSON方法,返回其自身的JSON数据格式。
var weather={
'city': '北京',
'cityid': '101010100',
'temp1': '31℃',
'temp2': '20℃',
'weather': '多云转晴',
toJSON:function(){
return this.city+this.weather+",最高温度"+this.temp1+",最低温度"+this.temp2;
}
};
JSON.stringify(weather);//""北京多云转晴,最高温度31℃,最低温度20℃""
综合以上几种情况,JSON.stringify()序列化对象的顺序如下:
①如果对象存在toJSON方法且能返回有效值,则调用该方法;否则,仍然按照默认顺序执行序列化。
②如果stringify()存在第二个参数,应用这个过滤器;
③对第②步返回的每个值进行序列化;
④如果存在第三个参数,执行相应的格式化。
三、JSON解析
JSON.parse()用来将JSON字符串解析成JavaScript对象。
该方法第一个参数要解析的JSON字符串;
第二个参数是一个函数还原函数。还原函数有两个参数key和value。如果还原函数返回undefined,则表示将该属性从结果中删除;如果返回其它值,则将该值插入到结果当中。在将日期字符串转换为Date对象时,经常用到还原函数.
var json = {
'city': '北京',
'cityid': '101010100',
'temp1': '19℃',
'temp2': '32℃',
'weather': '晴',
'ptime': new Date()
};
var text = JSON.stringify(json);
JSON.parse(text, function (key, value) {
switch (key) {
case 'ptime':
return new Date(value);//返回日期对象
case 'cityid':
return undefined;//删除该属性
default:
return value;
}
});
1.XHR对象
①IE6需要使用MSXML库中的一个ActiveX对象实现,而其他浏览器原生支持XHR对象。
function createXHR(){
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXobject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
for(var i=0, len = versions.length; I <len; i++){
try{
var xhr = new ActiveXObject(versions[i]);
Arguments.callee.activeXString = versions[i];
return xhr;
}catch(ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("No XHR object available");
}
}
1.1 XHR的用法
①open()方法
□接受3个参数:要发送的请求的类型(“get”、“post”等)、请求的URL和表示是异步发送请求的布尔值。
□参数URL是相对于执行代码的当前页面(当然也可以使用绝对路径);
□调用open()方法并不会真正发送请求,而只是启动一个请求以备发送。
②send()方法
□要发送特定的请求,必须使用send()方法启动。
□接受一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必须的。
□调用send()之后,请求就会被分派到服务器。
③相应的数据会自动填充XHR对象的属性,相关的属性简介如下:
□responseText:作为相应主体被返回的文本。
□responseXML:如果响应的内容是“text/xml”或“application/xml”,这个属性中将保存含着响应数据的XML DOM文档。
□status:响应的HTTP状态。
□statusText:HTTP状态的说明。
④处理响应的判断
□检查status属性,以确定响应成功返回。
□HTTP状态代码为200是成功的标志,此时responseText、responseXML应能访问。
□HTTP状态代码为304表示请求的资源没修改,可使用缓存值。
⑤同步请求
xhr.open("get", "example.txt", false);
xhr.send(null);
if( (xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.statusText);
}else{
alert("Request was unsuccessful:" + xhr.status);
}
⑥异步请求
1)发送异步请求还需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。取值如下:
□0:未初始化。尚未调用open()方法。
□1:启动。已调用open()方法,未调用send()方法。
□2:发送。已调用send()方法,但尚未接收到响应。
□3:接收。已接收到部分响应数据。
□4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
2)readyState值的变化会触发readyStatechange事件。由于并非所有浏览器支持DOM2级方法,因此用DOM0级添加处理程序。
var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if( (xhr.staus >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get","example.txt", true);
xhr.send(null);
⑦在接收到响应之前还可以调用abort()方法取消异步请求。xhr.abort();
1.2 HTTP头部信息
XHR对象提供了操作“请求头部”和“响应头部”信息的方法。
①请求头部
1)请求头部信息
□Accept:浏览器能够处理的内容类型。
□Accept-Charset:浏览器能够显示的字符集。
□Accept-Encoding:浏览器能够处理的压缩编码。
□connection:浏览器与服务器之间连接的类型。
□Cookie:当前页面设置的任何cookie。
□Host:发出请求的页面所在的域。
□Referer:发出请求的页面的URI。
□User-Agent:浏览器的用户代理字符串。
②setRequestHeader()方法可以设置自定义的请求头部信息。
□接收两个参数:头部字段名称和头部字段的值。
□要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前。
③getResponseHeader()方法,传入头部字段名称,可以取得相应的响应头部信息。
④getAllResponseHeader()方法,取得一个包含所有头部信息的长字符串。
1.3 GET请求
①常用语服务器查询信息。
②GET请求经常会发生查询字符串格式问题。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行编码。
③辅助向现有URL末尾添加查询字符串参数:
function addURLParam(url, name, value){
url += (url.indexOf("?") == -1 ? "?" : "&" );
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
1.4 POST请求
①通常用于向服务器发送应该被保存的数据。
②xhr.open("post","example.php",true);发送post请求的第二步就是向send方法中传入某些数据。
1.5浏览器差异
①IE
□IE为XHR对象添加了一个timeout属性,表示请求在等待响应。
□规定时间内没有接收到响应,就出发timeout事件,进而调用ontimeout事件处理程序。
②Firefox
1)load事件
2)progress事件
2.跨域请求
①IE中XDomainRequest对象
1)XDR与XHR区别
□cookie不会随请求发送,也不会随响应返回。
□只能设置请求头部信息中的Content-Type字段。
□不能访问响应头部信息。
□只支持GET和POST请求。
□XDR只能访问Access-Control-Allow-Origin头部设置为有当前域的资源。
2)所有XDR请求都是异步执行的,不能创建同步请求。
□返回请求之后,会触发load事件,响应的数据也会保存在response属性中。
□接收到响应后,只能访问响应的原始文本,没有办法确定响应的状态代码。
□响应有效会触发load事件,如果失败(包括响应中缺少Access-Control-Origin头部)就会触发error事件。
□XDR也支持timeout属性以及ontimeout事件处理程序。
□为了支持POST请求,XDR对象提供了ontentType属性,用来表示发送数据的格式。
□在请求返回前调用abort()方法可终止请求。
var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText);
};
xdr.timeout = 1000;
xdr.ontimeout = function(){
alert("Request took too long.");
};
xdr.open("get","http://www.xx.com/page/");
xdr.send(null);
②Firefox
1)要求远程资源有权决定自身是否可以被远程浏览器访问。
□这需要通过设置Access-Contro-Allow-Origin头部实现。
□要访问另一个域资源,可以使用标准XHR对象,并为open()方法传入一个绝对URL。
2)与IE中XDR对象不同,跨域XHR对象允许访问status和statusText属性,也支持同步请求。
3)跨域XHR的额外限制如下:
□不能使用setRequestHeader()设置自定义头部。
□不会发送也不会接受cookie
□getAllRequestponseHeaders()方法只能返回空字符串。
3.JSON
①JSON是纯文本,而不是JavaScript代码。JSON的设计意图在服务器端构建格式化的数据,然后再将数据发送给浏览器。
②由于JSON在JavaScript中相当于对象和数组,因此JSON字符串可以传递给eval()函数,让其解析并返回一个对象或数组的实例。
③如果你是自己编写代码来对JSON求值,最好将输入文本放在一对圆括号中。因为eval()在对输入的文本求值时,是将其作为JS代码而非数据格式看待。在对以左花括号开头的对象求值时,就好像是遇到一个没有名字的JavaScript语句,会导致错误。将文本放在一对圆括号中可以解决这个问题,因圆括号表示值而不是语句。
var object1 = eval("{}"); //抛出错误
var object2 = eval("({})"); //没有问题
var object3 = eval("(" + jsonText + ")"); //通用解决方案
3.1在Ajax中使用JSON
①Douglas Crockford的JSON序列化器/解析器。www.json.org/js.html
②在上述库中,有一个全局JSON对象,有两个方法:parse()和stringify()。
③parse()方法:
□两个参数:JSON文本和一个可选的过滤函数。在传入的文本是有效地JSON情况下,parse()方法返回传入数据的一个对象表示。
□例子:var object = JSON.parse("{}"); 与直接使用eval()不同的是,这里不需要传入的文本家圆括号(内部自动处理)。
□第二个参数是一个函数,这个函数以一个JSON键和值作为参数。要想让作为参数的键出现在结果对象中,该函数必须返回一个值。
var jsonText = "{\"name\":\"Nicholas\",\"age\":29,\"author\":true}";
var object = JSON.parse(jsonText,function(key,value){
switch(key){
case "age" : return value+1;
case "author" : return undefined;
default : return value;
}
});
alert(object.age); //30
alert(object.author); //undefined
④JSON同样也是向服务器发数据的流行格式。发送数据时,一般会把JSON放到POST请求主体中,而JSON对象的stringify()方法正是为此而设计。
⑤stringify()方法:
□三个参数:要序列化的对象、可选的替换函数(用于替换未受支持的JSON值)和可选的缩进说明符(可以是每个级别缩进的空格数,也可以是用来缩进的字符)。
var contact = {
name : "Nicholas C. Zakas",
email : "nicholas@some-domain-name.com"
};
var jsonText = JSON.stringify(contact);
alert(jsonText);
□JSON序列化支持的类型:字符串、数值、布尔值、null、对象、数组和Date(Date将被换成字符串形式)。其他不支持类型将被移除,可通过stringify()第二个参数所传入的函数改变行为。
3.2安全
①JSON缺点:使用eval(),有可能受到XSS攻击。
②建议使用Crockford的库,可妥当解析JSON字符串,过滤其中恶意代码。降低遭受代码式XSS攻击的可能性。
理解Json语法、解析Json、序列化Json
JSON (JavaScript Object Notation对象表示法)是一种结构化数据的格式,与JavaScript有相同的语法形式,但不属于JavaScript。支持多种编程语言。
20.1 语法
JSON的语法可以表示以下3种类型的值:
简单值:字符串、数值、布尔值、null (JSON不支持JavaScript的特殊值undefined)。
对象:一组有序键值对。每个键值对儿中的值可为简单值,也可以使复杂数据类型的值。
数组:一组有序的值的列表,通过数值索引来访问其中的值。数组的值可为简单值、对象或数组。
JSON不支持变量、函数 和 对象实例。
20.1.1 简单值
JS字符串与JSON字符串的最大区别是JSON字符串必须使用双引号(单引号会导致语法错误)。
布尔值和null也是有效的JSON形式。
20.1.2 对象
JSON中的对象和JS字面量稍微有一些不同。JSON中的对象要求给属性加引号:
{ "name" : "Nicholas", "age" : 29}
与JS的对象字面量相比,JSON对象有两个地方不一样。
1.没有声明变量(JSON中没有变量的概念)。
2.没有末尾的分号。
JSON中也可以像下面这样在对象中嵌入对象:
{ "name" : "Nicholas", "age" : 29, "school" : { "name" : "Merrimack College", "location" : "North Andover, MA" }}
20.1.3 数组
JSON数组采用的就是JS种的数组字面量形式。如:
[25, "hi", true]
JSON数组也没有变量和分号。把数组和对象结合起来,可以构成更复杂的数据集合。(其实也就是我们平时做需求时候经常用到的形式~)
20.2 解析与序列化
JSON流行的原因是,与XML数据结构相比,可以把JSON非常方便的解析为有用的JS对象,之后非常容易取到我们想要的数据。
20.2.1 JSON对象
早期的JSON解析器基本上就是使用JS的eval()函数。由于JSON是JS语法的子集,eval()函数可以解析、解释并返回JS对象和数组。
JSON对象有两个方法:stringify()和parse()。这两个方法分别用于把JS对象序列化为JSON字符串和把JSON字符串解析为原生JS值。例如:
var book = { title: "Professional JavaScript", authors: [ "Nicholas C. Zakas" ], edition: 3, year: 2011};var jsonText = JSON.stringify(book);
默认情况下,JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进,因此保存在jsonText中的字符串如下所示:
{"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],edition:3,year:2011}
在序列化JS对象时,所有函数、原型成员和值为undefined的属性都会被忽略。结果中最终都是值为有效JSON数据类型的实例属性。
将JSON字符串直接传递给JSON.parse()就可以得到相应的JS值。
var bookCopy = JSON.parse(jsonText);
创建的bookCopy与book具有相同的属性,但它们两个是独立的、没有任何关系的对象。
如果传给JSON.parse()的字符串不是有效的JSON,该方法会抛出错误。
20.2.2 序列化
除了JS对象,JSON.stringify()还有两个参数,一个是过滤器,可以是数组或函数,另一个是选项,表示是否在JSON字符串中保留缩进。
1.过滤器(过滤结果):数组、函数
数组过滤器:JSON.stringify()的结果 将只包含数组中列出的属性:
var book = { title: "Professional JS", authors: [ "Nicholas C. Zakas" ], edition: 3, year: 2011};var jsonText = JSON.stringify(book, ["title", "edition"]);
函数过滤器:函数有2个参数,为属性(键)名 和 属性值。属性名只能为字符串,非键值对结构的键名 为空字符串。
通过函数处理特定的属性。序列化的对象中的每个对象都要经过过滤器。
var jsonText = JSON.stringify(book, function(key, value){ switch(key){ case "authors": return value.join(",") case "year": return 5000; case "edition": return undefined; default: return value; }});
如果键为”authors”,将数组连接为一个字符串,如果键为”year”,将其值设为5000,如果键为”edition”,通过返回undefined删除该属性,最后要提供defaule项。返回:
{"title":"Professional JS","authors":"Nicholas C. Zakas","year":5000}
实际上,第一次调用函数过滤器时,传入的是一个空字符串,值为这个book对象。
2.字符串缩进
JSON.stringify()的第3个参数 用于控制结果的缩进和空白符。(换行符会在传入有效缩进参数时,自动添加)
当为数值时,表示每级缩进的空格数;当为非数值时,做为缩进字符(不再使用空格缩进)。
最大缩进数和缩进字符为10,超过时自动转换为10。
var jsonText = JSON.stringify(book, null, "--");
效果:
{----“title”: "Professional JS",----“authors”: [--------"Nicholas C. Zakas"----],----“edition”: 3,----“year”: 2011}
3.toJSON()方法
通过对象上调用toJSON()方法可返回其自身的JSON数据格式,可用于返回任何值;也可作为过滤器的补充,进行根精确的自定义序列化需求。
var book = { "title": "Professional JS", "authors": [ "Nicholas C. Zakas" ], edition: 3, year: 2011, toJSON: function(){ return this.title; }};var jsonText = JSON.stringify(book);
以上代码在book对象上定义了一个toJSON()方法,返回图书的书名。
toJSON()方法 会在序列化之前先执行。
toJSON()方法可以作为函数过滤器的补充,将一个对象传入JSON.stringify()后 的序列化顺序:
①若存在 而且 能通过toJSON()获取有效值,将先调用该方法。否则返回对象本身;
②若存在 第2参数,将①返回的值传入 过滤器;
③对②返回的每个值 进行相应的序列化;
④若存在 第3参数,对序列化后的数据 进行相应格式化。
20.2.3 解析选项
JSON.parse() 2个参数:JSON对象、函数(还原函数‘reviver’,与序列化的替换函数'replacer'具有相同签名:2个参数——键与值)
还原函数:若此函数返回undefined,将会删除相应的键,若返回其他值,则会被插入结果中。
var book = { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], edition: 3, year: 2011, releaseDate: new Date(2011, 11, 1)};var jsonText = JSON.stringify(book);var bookCopy = JSON.parse(jsonText, function(key, value){ if (key == "releaseDate"){ return new Date(value); } else { return value; }});
releaseDate属性保存着一个Date对象,序列化后,在bookCopy中又被还原成一个Date对象,故bookCopy.releaseDate才有一个Date对象,才可以调用getFullYear()方法。
20.3 小结
JSON是一个轻量级的数据格式,可以简化表示复杂数据结构得工作量。
JSON.stingify()和JSON.parse()方法分别用来实现,将对象序列化为JSON字符串或者将JSON数据解析为JS对象。
1、语法
JSON有3种类型的值:简单值、对象 和 数组。
简单值:字符串、数值、布尔值、null (JSON不支持JavaScript的特殊值undefined)
对象:一组无序键值对。值可为简单值,或对象和数组。
数组:一组有序键值对。值可为简单值,或对象和数组
JSON不支持变量、函数 和 对象实例。
1-1、简单型
JSON字符串必须使用双引号(单引号会导致语法错误)
1-2、对象
JSON对象的属性必须使用双引号:
{ "name":"xiaoming", "age":24
}
与JavaScript对象字面量的区别:无声明变量;无末尾分号。
1-3、数组
同样无声明对象;无末尾分号。
2、解析 与 序列化
2-1、JSON对象
早期JSON解析器使用JavaScript的eval()函数解析、解释 并 返回JavaScript对象和数组。ECMAScript5定义了全局对象JSON(支持IE8+ 等 主流浏览器)。
eval()对JSON数据结构求值存在风险,可能会执行恶意代码,故早期浏览器可使用shim:https://github.com/douglascrockford/JSON-js
JSON对象的两个方法:stringify()、parse()
stringify():将JavaScript对象 序列化 为JSON字符串。
stringify()
JSON.stringify()输出的JSON字符串 默认 不包含缩进、空格符 和 换行符。
序列化JavaScript对象时,所有函数、原型成员 和 值为undefined的属性 都会被忽略。
parse():将JSON字符串 解析 为原生JavaScript值
传给JSON.parse()的字符串不是有效JSON时,会抛出错误。
※即使stringify()之前和parse()后 两个对象属性相同,也是两个完全独立的对象。
2-2、序列化
JSON.stringify()有3个参数:JavaScript对象、过滤器、控制缩进等格式化
1-过滤器(过滤结果):数组、函数
数组过滤器:JSON.stringify()的结果 将只包含数组中列出的 属性:
数组过滤器
函数过滤器:函数有2个参数,为属性(键)名 和 属性值。属性名只能为字符串,非键值对结构的键名 为空字符串。
通过函数处理特定的属性。序列化的对象中的每个对象都要进过过滤器。
函数过滤器
☆实际上,第一次调用函数过滤器时,传入的是一个空字符串,值为这个book对象
2-字符串缩进
JSON.stringify()的第3个参数 用于控制结果的缩进和空白符。(换行符会在传入有效缩进参数时,自动添加)
当为数值时,表示每级缩进的空格数;
当为非数值时,做为缩进字符(不再使用空格缩进)。
※最大缩进数和缩进字符为10,超过时自动转换为10
View Code
3-toJSON()方法
toJSON()方法 可用于返回任何值;也可作为过滤器的补充,进行根精确的自定义序列化需求。
例子
☆☆☆☆☆
☆ 将一个对象传入JSON.stringify()后 的序列化 顺序:
①若存在 而且 能通过toJSON()获取有效值,将先调用该方法。否则返回对象本身;
②若存在 第2参数,将①返回的值传入 过滤器;
③对②返回的每个值 进行相应的序列化;
④若存在 第3参数,对序列化后的数据 进行相应格式化。
2-3、解析
JSON.parse() 2个参数:JSON对象、函数(还原函数‘reviver’,与序列化的替换函数'replacer'具有相同签名:2个参数——键与值)
还原函数:若此函数返回undefined,将会删除相应的键,若返回其他值,则会被插入结果中。
JSON是一个轻量级的数据格式,可以简化表示数据结构的工作量。在实际工作中,我们经常用它来传递数据,不过对于其使用的一些细节还是需要注意的。在ECMAScript5中定义了原生的JSON对象,可以用来将对象序列化为JSON字符串,或者将JSON数据解析为javascript对象。
一、JSON语法
JSON可以用来表示三种类型的值:简单值、对象和数组。对象和数组一般是JSON结构的最外层形式。
1.JSON简单值
可以在JSON中表示字符串、数值、布尔值、null。
例如:
5//数值类型
"hello json"//字符串类型
注意:
①JSON不支持js中的特殊值undefined;
②JSON字符串必须使用双引号,不能使用单引号。
③在实际应用中,JSON一般用来表示较复杂的数据结构,而简单值一般用作复杂数据结构中的一部分。
2.对象
JSON对象与JavaScript对象字面量对象的语法是类似的。
//JavaScript对象字面量表示
var jsWeatherinfo={
city:"北京",
cityid:"101010100",
weather:"多云转晴"
//JSON对象
{
"city":"北京",
"cityid":"101010100",
"weather":"多云转晴"
}
但是有几点不同:
①JSON中没有变量的概念,所以没有声明变量;
②JSON末尾没有分号;
③JSON对象中的属性名一定要使用双引号,而JavaScript对象中的属性引号是可有可无的。
3.数组
JSON数组采用的是javascript的数组字面量形式.
//JavaScript数组
var result=[1,true,"today"];
//JSON数组
[1,true,"today"]
区别:JSON数组没有末尾的分号,也没有声明变量.
二、JSON序列化
1.JSON对象
JavaScript的eval()函数可以用来解析JSON并返回JavaScript对象,不过eval()对JSON结构求值是存在风险的.因此,在ECMAScript5中新增了全局的JSON对象.JSON对象有两个方法:stringify()和parse().
stringify()用于把JavaScript对象序列化为JSON字符串;
parse()用于把JSON字符串解析为原生的JavaScript值.
var weather={
'city': '北京',
'cityid': '101010100',
'temp1': '31℃',
'temp2': '20℃',
'weather': '多云转晴',
'img1': 'd1.gif',
'img2': 'n0.gif',
'ptime': '11:00'
};
var text=JSON.stringify(weather);
var json=JSON.parse(text);
json.weather;//"多云转晴"
2.JSON.stringify()
JSON.stringify()方法有三个参数:
第一个参数是要序列化的JavaScript对象;
第二个参数是过滤器,可以是一个数组或者函数;
第三个参数是一个布尔值,表示是否在JSON字符串中保留缩进.
①过滤器
如果过滤器参数是数组,那么stringify()结果中只包含该数组中列出的属性.
var weather={
'city': '北京',
'cityid': '101010100',
'temp1': '31℃',
'temp2': '20℃',
'weather': '多云转晴',
'img1': 'd1.gif',
'img2': 'n0.gif',
'ptime': '11:00'
};
var text=JSON.stringify(weather,["city","weather","temp1","temp2"]);
//结果:"{"city":"北京","weather":"多云转晴","temp1":"31℃","temp2":"20℃"}"
如果过滤器是函数,传入的函数有两个参数:属性名和属性值.根据属性名来判断如何处理序列化对象中相应的属性.如果函数返回了undefined,那么相应的属性就会被忽略.
var text1 = JSON.stringify(weather, function (key, value) {
switch (key) {
case 'temp1':
return '最高温度' + value;
case 'temp2':
return '最低温度' + value;
case 'img1':
case 'img2':
case 'ptime':
return undefined;//属性被忽略
default:
return value;
}
});
//结果:"{"city":"北京","cityid":"101010100","temp1":"最高温度31℃","temp2":"最低温度20℃","weather":"多云转晴"}"
③字符串缩进
JSON.stringify()第三个参数用来控制结果中的缩进情况.
如果缩进参数传入的是数值,表示每个json字段缩进的空格数,但是最大缩进空格数不超过10.
var text2=JSON.stringify(weather,null,5)
如果缩进参数传入的是字符串,则表示JSON字符串中每个级别都使用该字符串作为缩进字符.不过该字符串也不能超过10个字符长.
var text3=JSON.stringify(weather,null,"--")
④toJSON()方法
如果JSON.stringify()不能满足某些对象的序列化需求,可以给对象自定义toJSON方法,返回其自身的JSON数据格式。
var weather={
'city': '北京',
'cityid': '101010100',
'temp1': '31℃',
'temp2': '20℃',
'weather': '多云转晴',
toJSON:function(){
return this.city+this.weather+",最高温度"+this.temp1+",最低温度"+this.temp2;
}
};
JSON.stringify(weather);//""北京多云转晴,最高温度31℃,最低温度20℃""
综合以上几种情况,JSON.stringify()序列化对象的顺序如下:
①如果对象存在toJSON方法且能返回有效值,则调用该方法;否则,仍然按照默认顺序执行序列化。
②如果stringify()存在第二个参数,应用这个过滤器;
③对第②步返回的每个值进行序列化;
④如果存在第三个参数,执行相应的格式化。
三、JSON解析
JSON.parse()用来将JSON字符串解析成JavaScript对象。
该方法第一个参数要解析的JSON字符串;
第二个参数是一个函数还原函数。还原函数有两个参数key和value。如果还原函数返回undefined,则表示将该属性从结果中删除;如果返回其它值,则将该值插入到结果当中。在将日期字符串转换为Date对象时,经常用到还原函数.
var json = {
'city': '北京',
'cityid': '101010100',
'temp1': '19℃',
'temp2': '32℃',
'weather': '晴',
'ptime': new Date()
};
var text = JSON.stringify(json);
JSON.parse(text, function (key, value) {
switch (key) {
case 'ptime':
return new Date(value);//返回日期对象
case 'cityid':
return undefined;//删除该属性
default:
return value;
}
});
1.XHR对象
①IE6需要使用MSXML库中的一个ActiveX对象实现,而其他浏览器原生支持XHR对象。
function createXHR(){
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXobject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
for(var i=0, len = versions.length; I <len; i++){
try{
var xhr = new ActiveXObject(versions[i]);
Arguments.callee.activeXString = versions[i];
return xhr;
}catch(ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("No XHR object available");
}
}
1.1 XHR的用法
①open()方法
□接受3个参数:要发送的请求的类型(“get”、“post”等)、请求的URL和表示是异步发送请求的布尔值。
□参数URL是相对于执行代码的当前页面(当然也可以使用绝对路径);
□调用open()方法并不会真正发送请求,而只是启动一个请求以备发送。
②send()方法
□要发送特定的请求,必须使用send()方法启动。
□接受一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必须的。
□调用send()之后,请求就会被分派到服务器。
③相应的数据会自动填充XHR对象的属性,相关的属性简介如下:
□responseText:作为相应主体被返回的文本。
□responseXML:如果响应的内容是“text/xml”或“application/xml”,这个属性中将保存含着响应数据的XML DOM文档。
□status:响应的HTTP状态。
□statusText:HTTP状态的说明。
④处理响应的判断
□检查status属性,以确定响应成功返回。
□HTTP状态代码为200是成功的标志,此时responseText、responseXML应能访问。
□HTTP状态代码为304表示请求的资源没修改,可使用缓存值。
⑤同步请求
xhr.open("get", "example.txt", false);
xhr.send(null);
if( (xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.statusText);
}else{
alert("Request was unsuccessful:" + xhr.status);
}
⑥异步请求
1)发送异步请求还需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。取值如下:
□0:未初始化。尚未调用open()方法。
□1:启动。已调用open()方法,未调用send()方法。
□2:发送。已调用send()方法,但尚未接收到响应。
□3:接收。已接收到部分响应数据。
□4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
2)readyState值的变化会触发readyStatechange事件。由于并非所有浏览器支持DOM2级方法,因此用DOM0级添加处理程序。
var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if( (xhr.staus >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get","example.txt", true);
xhr.send(null);
⑦在接收到响应之前还可以调用abort()方法取消异步请求。xhr.abort();
1.2 HTTP头部信息
XHR对象提供了操作“请求头部”和“响应头部”信息的方法。
①请求头部
1)请求头部信息
□Accept:浏览器能够处理的内容类型。
□Accept-Charset:浏览器能够显示的字符集。
□Accept-Encoding:浏览器能够处理的压缩编码。
□connection:浏览器与服务器之间连接的类型。
□Cookie:当前页面设置的任何cookie。
□Host:发出请求的页面所在的域。
□Referer:发出请求的页面的URI。
□User-Agent:浏览器的用户代理字符串。
②setRequestHeader()方法可以设置自定义的请求头部信息。
□接收两个参数:头部字段名称和头部字段的值。
□要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前。
③getResponseHeader()方法,传入头部字段名称,可以取得相应的响应头部信息。
④getAllResponseHeader()方法,取得一个包含所有头部信息的长字符串。
1.3 GET请求
①常用语服务器查询信息。
②GET请求经常会发生查询字符串格式问题。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行编码。
③辅助向现有URL末尾添加查询字符串参数:
function addURLParam(url, name, value){
url += (url.indexOf("?") == -1 ? "?" : "&" );
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
1.4 POST请求
①通常用于向服务器发送应该被保存的数据。
②xhr.open("post","example.php",true);发送post请求的第二步就是向send方法中传入某些数据。
1.5浏览器差异
①IE
□IE为XHR对象添加了一个timeout属性,表示请求在等待响应。
□规定时间内没有接收到响应,就出发timeout事件,进而调用ontimeout事件处理程序。
②Firefox
1)load事件
2)progress事件
2.跨域请求
①IE中XDomainRequest对象
1)XDR与XHR区别
□cookie不会随请求发送,也不会随响应返回。
□只能设置请求头部信息中的Content-Type字段。
□不能访问响应头部信息。
□只支持GET和POST请求。
□XDR只能访问Access-Control-Allow-Origin头部设置为有当前域的资源。
2)所有XDR请求都是异步执行的,不能创建同步请求。
□返回请求之后,会触发load事件,响应的数据也会保存在response属性中。
□接收到响应后,只能访问响应的原始文本,没有办法确定响应的状态代码。
□响应有效会触发load事件,如果失败(包括响应中缺少Access-Control-Origin头部)就会触发error事件。
□XDR也支持timeout属性以及ontimeout事件处理程序。
□为了支持POST请求,XDR对象提供了ontentType属性,用来表示发送数据的格式。
□在请求返回前调用abort()方法可终止请求。
var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText);
};
xdr.timeout = 1000;
xdr.ontimeout = function(){
alert("Request took too long.");
};
xdr.open("get","http://www.xx.com/page/");
xdr.send(null);
②Firefox
1)要求远程资源有权决定自身是否可以被远程浏览器访问。
□这需要通过设置Access-Contro-Allow-Origin头部实现。
□要访问另一个域资源,可以使用标准XHR对象,并为open()方法传入一个绝对URL。
2)与IE中XDR对象不同,跨域XHR对象允许访问status和statusText属性,也支持同步请求。
3)跨域XHR的额外限制如下:
□不能使用setRequestHeader()设置自定义头部。
□不会发送也不会接受cookie
□getAllRequestponseHeaders()方法只能返回空字符串。
3.JSON
①JSON是纯文本,而不是JavaScript代码。JSON的设计意图在服务器端构建格式化的数据,然后再将数据发送给浏览器。
②由于JSON在JavaScript中相当于对象和数组,因此JSON字符串可以传递给eval()函数,让其解析并返回一个对象或数组的实例。
③如果你是自己编写代码来对JSON求值,最好将输入文本放在一对圆括号中。因为eval()在对输入的文本求值时,是将其作为JS代码而非数据格式看待。在对以左花括号开头的对象求值时,就好像是遇到一个没有名字的JavaScript语句,会导致错误。将文本放在一对圆括号中可以解决这个问题,因圆括号表示值而不是语句。
var object1 = eval("{}"); //抛出错误
var object2 = eval("({})"); //没有问题
var object3 = eval("(" + jsonText + ")"); //通用解决方案
3.1在Ajax中使用JSON
①Douglas Crockford的JSON序列化器/解析器。www.json.org/js.html
②在上述库中,有一个全局JSON对象,有两个方法:parse()和stringify()。
③parse()方法:
□两个参数:JSON文本和一个可选的过滤函数。在传入的文本是有效地JSON情况下,parse()方法返回传入数据的一个对象表示。
□例子:var object = JSON.parse("{}"); 与直接使用eval()不同的是,这里不需要传入的文本家圆括号(内部自动处理)。
□第二个参数是一个函数,这个函数以一个JSON键和值作为参数。要想让作为参数的键出现在结果对象中,该函数必须返回一个值。
var jsonText = "{\"name\":\"Nicholas\",\"age\":29,\"author\":true}";
var object = JSON.parse(jsonText,function(key,value){
switch(key){
case "age" : return value+1;
case "author" : return undefined;
default : return value;
}
});
alert(object.age); //30
alert(object.author); //undefined
④JSON同样也是向服务器发数据的流行格式。发送数据时,一般会把JSON放到POST请求主体中,而JSON对象的stringify()方法正是为此而设计。
⑤stringify()方法:
□三个参数:要序列化的对象、可选的替换函数(用于替换未受支持的JSON值)和可选的缩进说明符(可以是每个级别缩进的空格数,也可以是用来缩进的字符)。
var contact = {
name : "Nicholas C. Zakas",
email : "nicholas@some-domain-name.com"
};
var jsonText = JSON.stringify(contact);
alert(jsonText);
□JSON序列化支持的类型:字符串、数值、布尔值、null、对象、数组和Date(Date将被换成字符串形式)。其他不支持类型将被移除,可通过stringify()第二个参数所传入的函数改变行为。
3.2安全
①JSON缺点:使用eval(),有可能受到XSS攻击。
②建议使用Crockford的库,可妥当解析JSON字符串,过滤其中恶意代码。降低遭受代码式XSS攻击的可能性。
理解Json语法、解析Json、序列化Json
JSON (JavaScript Object Notation对象表示法)是一种结构化数据的格式,与JavaScript有相同的语法形式,但不属于JavaScript。支持多种编程语言。
20.1 语法
JSON的语法可以表示以下3种类型的值:
简单值:字符串、数值、布尔值、null (JSON不支持JavaScript的特殊值undefined)。
对象:一组有序键值对。每个键值对儿中的值可为简单值,也可以使复杂数据类型的值。
数组:一组有序的值的列表,通过数值索引来访问其中的值。数组的值可为简单值、对象或数组。
JSON不支持变量、函数 和 对象实例。
20.1.1 简单值
JS字符串与JSON字符串的最大区别是JSON字符串必须使用双引号(单引号会导致语法错误)。
布尔值和null也是有效的JSON形式。
20.1.2 对象
JSON中的对象和JS字面量稍微有一些不同。JSON中的对象要求给属性加引号:
{ "name" : "Nicholas", "age" : 29}
与JS的对象字面量相比,JSON对象有两个地方不一样。
1.没有声明变量(JSON中没有变量的概念)。
2.没有末尾的分号。
JSON中也可以像下面这样在对象中嵌入对象:
{ "name" : "Nicholas", "age" : 29, "school" : { "name" : "Merrimack College", "location" : "North Andover, MA" }}
20.1.3 数组
JSON数组采用的就是JS种的数组字面量形式。如:
[25, "hi", true]
JSON数组也没有变量和分号。把数组和对象结合起来,可以构成更复杂的数据集合。(其实也就是我们平时做需求时候经常用到的形式~)
20.2 解析与序列化
JSON流行的原因是,与XML数据结构相比,可以把JSON非常方便的解析为有用的JS对象,之后非常容易取到我们想要的数据。
20.2.1 JSON对象
早期的JSON解析器基本上就是使用JS的eval()函数。由于JSON是JS语法的子集,eval()函数可以解析、解释并返回JS对象和数组。
JSON对象有两个方法:stringify()和parse()。这两个方法分别用于把JS对象序列化为JSON字符串和把JSON字符串解析为原生JS值。例如:
var book = { title: "Professional JavaScript", authors: [ "Nicholas C. Zakas" ], edition: 3, year: 2011};var jsonText = JSON.stringify(book);
默认情况下,JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进,因此保存在jsonText中的字符串如下所示:
{"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],edition:3,year:2011}
在序列化JS对象时,所有函数、原型成员和值为undefined的属性都会被忽略。结果中最终都是值为有效JSON数据类型的实例属性。
将JSON字符串直接传递给JSON.parse()就可以得到相应的JS值。
var bookCopy = JSON.parse(jsonText);
创建的bookCopy与book具有相同的属性,但它们两个是独立的、没有任何关系的对象。
如果传给JSON.parse()的字符串不是有效的JSON,该方法会抛出错误。
20.2.2 序列化
除了JS对象,JSON.stringify()还有两个参数,一个是过滤器,可以是数组或函数,另一个是选项,表示是否在JSON字符串中保留缩进。
1.过滤器(过滤结果):数组、函数
数组过滤器:JSON.stringify()的结果 将只包含数组中列出的属性:
var book = { title: "Professional JS", authors: [ "Nicholas C. Zakas" ], edition: 3, year: 2011};var jsonText = JSON.stringify(book, ["title", "edition"]);
函数过滤器:函数有2个参数,为属性(键)名 和 属性值。属性名只能为字符串,非键值对结构的键名 为空字符串。
通过函数处理特定的属性。序列化的对象中的每个对象都要经过过滤器。
var jsonText = JSON.stringify(book, function(key, value){ switch(key){ case "authors": return value.join(",") case "year": return 5000; case "edition": return undefined; default: return value; }});
如果键为”authors”,将数组连接为一个字符串,如果键为”year”,将其值设为5000,如果键为”edition”,通过返回undefined删除该属性,最后要提供defaule项。返回:
{"title":"Professional JS","authors":"Nicholas C. Zakas","year":5000}
实际上,第一次调用函数过滤器时,传入的是一个空字符串,值为这个book对象。
2.字符串缩进
JSON.stringify()的第3个参数 用于控制结果的缩进和空白符。(换行符会在传入有效缩进参数时,自动添加)
当为数值时,表示每级缩进的空格数;当为非数值时,做为缩进字符(不再使用空格缩进)。
最大缩进数和缩进字符为10,超过时自动转换为10。
var jsonText = JSON.stringify(book, null, "--");
效果:
{----“title”: "Professional JS",----“authors”: [--------"Nicholas C. Zakas"----],----“edition”: 3,----“year”: 2011}
3.toJSON()方法
通过对象上调用toJSON()方法可返回其自身的JSON数据格式,可用于返回任何值;也可作为过滤器的补充,进行根精确的自定义序列化需求。
var book = { "title": "Professional JS", "authors": [ "Nicholas C. Zakas" ], edition: 3, year: 2011, toJSON: function(){ return this.title; }};var jsonText = JSON.stringify(book);
以上代码在book对象上定义了一个toJSON()方法,返回图书的书名。
toJSON()方法 会在序列化之前先执行。
toJSON()方法可以作为函数过滤器的补充,将一个对象传入JSON.stringify()后 的序列化顺序:
①若存在 而且 能通过toJSON()获取有效值,将先调用该方法。否则返回对象本身;
②若存在 第2参数,将①返回的值传入 过滤器;
③对②返回的每个值 进行相应的序列化;
④若存在 第3参数,对序列化后的数据 进行相应格式化。
20.2.3 解析选项
JSON.parse() 2个参数:JSON对象、函数(还原函数‘reviver’,与序列化的替换函数'replacer'具有相同签名:2个参数——键与值)
还原函数:若此函数返回undefined,将会删除相应的键,若返回其他值,则会被插入结果中。
var book = { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], edition: 3, year: 2011, releaseDate: new Date(2011, 11, 1)};var jsonText = JSON.stringify(book);var bookCopy = JSON.parse(jsonText, function(key, value){ if (key == "releaseDate"){ return new Date(value); } else { return value; }});
releaseDate属性保存着一个Date对象,序列化后,在bookCopy中又被还原成一个Date对象,故bookCopy.releaseDate才有一个Date对象,才可以调用getFullYear()方法。
20.3 小结
JSON是一个轻量级的数据格式,可以简化表示复杂数据结构得工作量。
JSON.stingify()和JSON.parse()方法分别用来实现,将对象序列化为JSON字符串或者将JSON数据解析为JS对象。