JavaScript学习笔记6--JSON与AJAX

  |  

前言

学习一下JavaScript关于JSON和AJAX部分的内容。


16

语法

JSON的语法可以表示以下三种类型的值:

  • 简单值:使用与JavaScript相同的语法,可以在JSON中表示字符串、数值、布尔值和null,但是不支持undefined
  • 对象
  • 数组

JSON不支持变量、函数或对象实例

对象:

JSON对象没有什么声明变量,末尾没有分号,对象属性必须加双引号

数组:

JSON数组没有变量和分号

解析与序列化

JSON对象有两个方法:stringif()和parse()。在最简单的情况下,这两个方法分别用于把JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript值

序列化选项

JSON.stringify()除了要序列化的JavaScript对向外,还可以接收两个参数。第一个参数是个过滤器,可以是个数组,也可以是一个函数;第二个参数是一个选项,表示是否在JSON字符串中保留缩进。

如果过滤器参数是个数组,那么JSON.stringify()的结果中将只包含数组中列出的属性。

如果过滤器参数是一个函数,那么传入的函数接收两个参数,属性名和属性值。

第三个参数用于控制结果中的缩进和空白符。如果这个参数是一个数值,那么它表示的是每个级别缩进的空格数,最大为10,超过10转换为10

toJSON方法

有时候,JSON.stringify()还是不能满足对某些对象进行自定义序列化的需求。在这些情况下可以给对象定义toJSON()方法,返回其自身的JSON数据格式。

1
2
3
4
5
6
7
8
9
10
11
12
var book = {
"title": "Professional JavaScript",
"authors": [
"Nicholas C.Zakas"
],
edition: 3,
year: 2011,
toJSON: function() {
return this.title
}
};
var jsonText = JSON.stringify(book);

JSON.stringify()序列化对象的顺序:

  • 如果存在toJSON()方法而且能通过它取得有效的值,则调用该方法,否则返回对象本身
  • 如果提供了第二个参数,应用这个函数过滤器,传入函数过滤器的值是第一步返回的值
  • 对第二部返回的每个值进行相应的序列化
  • 如果提供了第三个参数,则执行相应的格式化

解析选项

JSON.parse()方法也可以接收另一个参数,该参数是一个函数,将在每个键值对上调用,被称为还原函数。接收两个参数,一个键和一个值,而且都需要返回一个值。

XMLHttpRequest对象

在使用XHR对象前,要调用的第一个方法是open(),它接收三个参数:要发送的请求的类型

、请求的URL和表示是否异步发送请求的布尔值,例

1
2
var xhr = new XMLHttpRequest;
xhr.open("get", "example.php", false);

这段代码会启动一个针对example.php的GET请求。有两点需要注意的是:

  • URL可以采用相对路径或者绝对路径
  • 调用open()方法并不真正发送请求,而是启动一个请求以备发送

要发送特定的请求,需要再调用send()方法:

1
xhr.send(null);

send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对某些浏览器来说是必须的。

在接收到响应后,响应的数据会自动填充XHR对象的属性,相关属性有:

  • responseText:作为响应主体被返回的文本
  • responseXML:如果相应的内容类型为”text/xml”或”application/xml”,这个属性中将保存着响应数据的XML DOM文档
  • status:响应的HTTP状态
  • statusText:HTTP状态的说明

在接收到响应后,需要检查status属性,以确定响应已成功返回。一般来说HTTP状态码为200作为成功的标志,304表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本。,所以我们可以这样检测状态码:

1
2
3
4
5
6
7
xhr.open("get", "example.php", false);
xhr.send(null);
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}

建议使用status来决定下一步的操作,而不是使用statusText,后者在跨浏览器使用时不太可靠。除此之外,无论内容类型是什么,响应主题的内容都会保存到responseText属性中;而对于非XML数据而言,responseXML属性的值将为null。

之前我们考虑的都是在同步请求的情况,但在很多情况下我们还是要发送异步请求,才能让JavaScript继续执行而不必等待响应。这是我们们就要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段。属性可取的值有:

  • 0:未初始化。尚未调用open()方法
  • 1:启动。已经调用open()方法,但尚未调用send()方法
  • 2:发送。已经调用send()方法,但尚未接收到响应
  • 3:接收。已经接收到部分相应数据
  • 4:完成。已经接收到全部相应数据,而且已经可以在客户端使用了

只要readyState属性的值也有一个值变成另一个值,都会触发一次readystatechange事件。通常我们支队readyState值为4的阶段感兴趣,因为这时数据已经准备就绪了。所以我们可以检测该值的变化

1
2
3
4
5
6
7
8
9
10
11
12
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
} else {
console.log("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "a.php", true);
xhr.send(null);

此外,我们可以使用xhr.abort()方法在接收到响应之前取消异步请求。调用这个方法以后,XHR对象会停止触发时间,而且也不再允许访问任何与响应相关的对象属性。

在终止请求之后,还应该对XHR对象进行解引用操作。由于内存的原因,不建议重用XHR对象。

HTTP头部信息

默认情况下,在发送XHR请求的同时,还会发送下列头部信息:

  • Accept:浏览器能够处理的内容类型
  • Accept-Charset:浏览器能够处理的字符集
  • Accept-Encoding:浏览器能够处理的压缩编码
  • Accept-Language:浏览器当前设置的语言
  • Connection:浏览器与服务器之间连接的类型。
  • Cookie:当前页面设置的任何Cookie
  • Host:发送请求的页面所在的域
  • Referer:发送请求的页面的URI
  • User-Agent:浏览器的用户代理字符串

除了默认发送的头部信息,我们可以使用setRequestHeader()方法发送自定义的请求头部信息。这个方法接受两个参数:头部字段的名称和头部字段的值。要成功发送请求头部信息必须在调用open()方法之后且调用send()方法之前调用setRequestHeader()

1
2
3
xhr.open(methods, url, true);
xhr.setRequestHeader("MyHeader", "MyValue");
xhr.send(null);

调用XHR对象的getResponseHeader()方法并传入头部字段名称,可以获得相应的响应头部信息。而调用getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。

GET请求

可以将查询字符串参数追加到URL末尾,一遍将信息发送给服务器。对于XHR而言,位于open()方法的URL参数末尾的查询字符串必须经过正确编码。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行编码,然后才能放到URL的末尾。

可以使用类似这样的工具函数来给URL加参数:

1
2
3
4
5
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}

POST请求

在open()方法第一个参数的位置传入”post”,就可以初始化一个post请求。

发送POST请求的第二步就是向send()方法中传入某些数据。由于XHR最初的设计主要是为了处理XML,因此可以在此处传入XML DOM文档,传入的文档经过序列化之后将作为请求主体被提交到服务器。当然,也可以在此传入任何想发送到服务器的字符串。

默认情况下,服务器对POST请求和提交Web表单的请求并不会做同样的处理。但是我们可一通过过XHR来模仿表单提交:首先将Content-Type头部信息设置为application/x-www-form-urlencoded,也就是表单提交时的内容类型,其次是以适当的格式创建一个字符串。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("Request was unsuccessful: " + xhr.status);
}
}
}
xhr.open("post", "post.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("username=user&password=pass");

与GET请求相比,POST请求会消耗更多的资源。从性能的角度来看,以发送相同的数据记,GET请求的速度最多达到POST的两倍。

XMLHttpRequest2级

FormData

XMLHttpRequest2级定义了FormData类型。FormData为序列化表单以及创建与表单格式相同的数据提供了遍历。例:

1
2
var data = new FormData();
data.append("name", "Nicholas");

append()方法接收两个参数:键和值,分别对应表单字段的名字和字段中包含的值。而通过向FormData构造函数中传入表单元素,也可以用表单元素的数据预先向其中填入键值对。

1
var data = new FormData(document.forms[0]);

使用FormData的方便之处体现在不必明确的在XHR对象上设置请求头部。XHR对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息。

超时设定

IE8为XHR对象添加了一个timeout属性,表示请求在等待响应多少毫秒后终止。在给timeout设置一个数值后,如果在规定的时间内浏览器还没接收到响应,那么就会出啊发timeout事件,进而会调用ontimeout事件处理程序。例:

1
2
3
4
xhr.timeout = 1000;
xhr.ontimeout = function() {
alert("request did not return in a second");
}

overrideMimeType()方法

overrideMimeType()方法用于重写XHR响应的MIME类型。因为返回响应的MIME类型决定了XHR对象如何处理它,所以提供一种方法能够重写服务器返回的MIME类型十分必要。

比如,服务器返回的MIME类型是text/plain,但数据中包含的是XML。根据MIME类型,即使数据是XML,responseXML属性中仍然是null。而通过调用overrideMimeType()方法,可以保证把响应当作XML而非纯文本来处理。例:

1
2
3
4
var xhr = createXHR();
xhr.open("get", "text.php", true);
xhr.overrideMimeType("text/xml");
xhr.send(null)

这个例子强迫XHR对象将响应当作XML而非纯文本来处理。调用overrideMimeType()必须在send()方法之前,才能保证重写响应的MIME类型。

文章目录
  1. 1. 语法
  2. 2. 解析与序列化
    1. 2.1. 序列化选项
    2. 2.2. toJSON方法
    3. 2.3. 解析选项
  3. 3. XMLHttpRequest对象
    1. 3.1. HTTP头部信息
    2. 3.2. GET请求
    3. 3.3. POST请求
  4. 4. XMLHttpRequest2级
    1. 4.1. FormData
    2. 4.2. 超时设定
    3. 4.3. overrideMimeType()方法