《JavaScript高级程序设计》读书笔记(五)

Author Avatar
wshunli 11月 08, 2017
  • 在其它设备中阅读本文章

《JavaScript高级程序设计》读书笔记

(五) 学习 JavaScript 对各数据载体的操作方法(如JSON、XML),学会 Ajax 的使用方法。(18-21章)

第十八章 JavaScript 与 XML

浏览器对 XML DOM 的支持

如何检测浏览器是否支持DOM2级XML:

var hasXmlDom = document.implementation.hasFeature("XML","2.0");

在支持DOM2级的浏览器中创建一个空白XML:

var xmldom = document.implemention.createDocument(namespaceUri,root,docype);

通过 JavaScript 处理XML时,通常只使用参数root,这个参数指定的是XML DOM文档元素的标签名。

var xmldom = document.implementation.createDocument("","root",null);
console.log(xmldom.documentElement.tagName);  //"root"
var child = xmldom.createElement("child");
xmldom.documentElement.appendChild(child);

DOMParser 类型:将 XML 解析为 DOM 文档。

XMLSerializer 类型:将 DOM 文档序列化为 XML 字符串。

var parser = new DOMParser();
var xmldom = parser.parseFromString("<root><child/></root>", "text/xml");
//convert back into XML
var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmldom);
console.log(xml);

浏览器对XPath的支持

XPath 是设计用来在 DOM 文档中查找节点的一种手段。

浏览器对XSLT的支持

XSLT 是与 XML 相关的一种技术,它利用 XPath 将文档从一种表现形式转换成另一种表现形式。

第十九章 E4X

E4X 本身不是一门语言,它只是 ECMAScript 语言的可选扩展。
就其本身而言,E4X 为处理 XML 定义了新的语法,也定义了特定于 XML 的对象。

第二十章 JSON

JSON(Javascript Object Notaion,Javascript对象表示法)是一种数据格式。

语法

JSON有3种类型的值:简单值、对象 和 数组。

  • 简单值:字符串、数值、布尔值、null(JSON不支持JavaScript的特殊值undefined)。
  • 对象:一组无序键值对。值可为简单值,或对象和数组。
  • 数组:一组有序值的列表。值可为简单值,或对象和数组。

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

简单值:最简单的 JSON 数据形式就是简单值。

6
"Hello World!" //必须为双引号

布尔值和 null 也是有效的 JSON 数据形式,但简单值往往是复杂数据结构的一部分。

对象

// JavaScript对象字面量:
var object = {
  "name": "Nicholas",
  "age": 29
};
// JSON 表示方式如下:
{
  "name": "Nicholas",
  "age": 29
}

JSON 对象 与 JavaScript 的对象字面量相比:首先,没有声明变量(JSON 中没有变量的概念);其次,没有末尾的分号;JSON 对象的属性必须加双引号。

数组:JSON 数组采用的就是 JavaScript 中的数组字面量形式。

// JavaScript 中的数组字面量:
var values = [25, "hi", true];
// JSON 表示数组:
[25, "hi", true]

解析与序列化

ECMAScript5 对解析 JSON 进行了规范,定义了全局对象 JSON。

JSON 对象有两个方法:stringify() 和 parse(),分别用于把 JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值。

var book = {
        title: "Professional JavaScript",
        authors: [
            "Nicholas C. Zakas"
        ],
        edition: 3,
        year: 2011
    };
var jsonText = JSON.stringify(book, ["title", "edition"]);
console.log(jsonText);
// {"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011}
var bookCopy =JSON.parse(jsonText);

序列化选项: JSON.stringify() 除了要序列化的 JavaScript 对象外,还可以接收另外两个参数指定以不同的方式序列化。
第一个参数是数据,第二个参数是个过滤器,可以是一个数组或函数;第三个参数是一个选项,表示是否在 JSON 字符串中保留缩进。

1.过滤结果:

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

var jsonText = JSON.stringify(book, ["title", "edition"]);
//{"title":"Professional JavaScript","edition":3}

如果过滤器参数是函数,传入的函数接收两个参数,属性(键)名和属性值。

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;
   }
});
//{"title":"Professional JavaScript","authors":"Nicholas C. Zakas","year":5000}

2.字符串缩进

JSON.stringify()方法的第三个参数用于控制结果中的缩进和空白符。
如果这个参数是一个数值,那它表示的是每个级别缩进的空格数。

var jsonText = JSON.stringify(book, null, 4);

结果:

{
    'title': 'Professional JavaScript',
    'authors': [
        'Nicholas C. Zakas'
    ],
    'edition': 3,
    'year': 2011
}

如果缩进参数是一个字符串而非数值,则这个字符串将在 JSON 字符串中被用作缩进字符(不再使用空格)。

var jsonText = JSON.stringify(book, null, " - -");

结果:

{
 - -'title': 'Professional JavaScript',
 - -'authors': [
 - - - -'Nicholas C. Zakas'
 - -],
 - -'edition': 3,
 - -'year': 2011
}

缩进字符串最长不能超过 10 个字符长。如果字符串长度超过了 10 个,结果中将只出现前 10 个字符。

3.toJSON()方法

给对象自定义 toJSON() 方法,返回其自身的 JSON 数据格式。

var book = {
        "title": "Professional JavaScript",
        "authors": [
            "Nicholas C. Zakas"
        ],
        edition: 3,
        year: 2011,
        toJSON: function(){
            return this.title;
        }
    };
var jsonText = JSON.stringify(book);
console.log(jsonText);

假设把一个对象传入 JSON.stringify(),序列化该对象的顺序如下:
(1) 如果存在 toJSON() 方法而且能通过它取得有效的值,则调用该方法。否则,返回对象本身。
(2) 如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第(1)步返回的值。
(3) 对第(2)步返回的每个值进行相应的序列化。
(4) 如果提供了第三个参数,执行相应的格式化。

解析选项:JSON.parse() 方法也可以接收另一个参数,该参数是一个函数(还原函数),将在每个键值对儿上调用。
如果还原函数返回 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);
console.log(jsonText);
var bookCopy = JSON.parse(jsonText, function(key, value){
    if (key == "releaseDate"){
        return undefined;
    } else {
        return value;
    }
});
console.log("releaseDate" in bookCopy);

第二十一章 Ajax 与 Comet

Ajax(Asynchronous Javascript + XML)技术的核心是 XMLHttpRequest 对象,即: XHR。
它所指的仅仅是无须刷新页面即可从服务器端获取数据的技术,其通信与数据格式无关,并不一定是 XML 数据。

XMLHttpRequest 对象

XHR的用法

使用 XMLHttpRequest 构造函数来创建 XHR 对象。

var xhr = new XMLHttpRequest();

使用 XHR对象的时候,要调用的第一个方法是open(),它接受3个参数:

  1. 要发送请求的类型,如: get/post
  2. 请求的 url
  3. 是否异步发送请求,这个参数是一个布尔值

再调用 send() 方法,才会真正发起 ajax 请求。

xhr.open('get', 'example.php', false)
xhr.send(null);

本例中的请求是同步的,Javascript 代码会等到服务器响应之后再执行。
收到响应后,响应的数据会自动填充 XHR 对象的属性,相关的属性有:

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

发送异步请求:JavaScript 继续执行而不必等待。
此时,我们可以检测readyState属性,该属性表示请求/响应过程的当前活动阶段。它的可取值有如下几种:

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

readyState 属性的每一次变化,都会触发一次 readyStateChange 事件,我们可以利用这个事件来检测 readyState 值。

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('fail, ' + xhr.status);
        }
    }
}
xhr.open('get', 'example.txt', true);
xhr.send(null);

在接收到响应之前,可以调用 abort() 方法来取消异步请求。

xhr.abort();

HTTP 头部信息:XHR 对象提供了操作头部信息的方法,包括对请求头部和响应头部的操作。

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

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

setRequestHeader():自定义的头部信息。

xhr.open('get', 'example.txt', true);
xhr.setRequestHeader("MySite", "wshunli.com");
xhr.send(null);

getResponseHeader():获取响应头部信息。

var mySite = xhr.getResponseHeader('MySite'); // wshunli.com

getAllResponseHeaders():在服务器端,也可以利用头部信息向浏览器发送额外的结构化数据。

var allHeaders = xhr.getAllResponseHeaders();
// 返回内容
Date: Sun, 14 Nov 2004 18:04:22 GMT
Server: Apache/1.3.29 (Unix)
Vary: Accept
X-Powerd-By: PHP/4.3.8
Connection: close
Content-Type: text/html; charset=iso-8859-1

GET 请求:向服务器查询某些信息。

xhr.open("get", "example.php?name1=value1&name2=value2", true);

POST 请求:向服务器发送应该被保存的数据。

xhr.open("post", "post.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("my-form");
xhr.send(serialize(form));

XMLHttpRequest 2 级

FormData

XMLHttpRequest 2 级定义了 FormData 类型,来处理表单数据的序列化,以及创建与表单格式相同的数据。

var data = new FormData();
// 添加键值对
data.append('site', 'wshunli.com');
// 直接传入表单元素
var data = new FormData(document.forms[0]);

创建 FromData 的实例后,就可以传给 XHR 的 send() 方法。

var xhr = new XMLHttpRequest();
 ···
var form = document.getElementById('site-info');
xhr.send(new FormData(form));

XHR 对象能够识别传入的数据类型是 FormData 的实例,并配置适当的头部信息。

超时设定

XHR 对象添加了一个 timeout 属性,表示请求在等待多少毫秒之后就终止。

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    try{
        if(xhr.readyState == 4){
            if( (xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                console.log(xhr.responseText);
            }
            else{
                console.log('fail, ' + xhr.status);
            }
        }
    }
    catch(ex){
    }
}
xhr.open('get', 'example.php', true);
xhr.timeout = 1000; // 1秒超时,仅适用IE8+
xhr.ontimeout = function(){
    console.log('fail, timeout');
}
xhr.send(null);

在给 timeout 设置一个数值后,如果在规定时间内浏览器没有接收到响应信息,就会触发 timeout 事件,进而会调用 ontimeout 事件处理程序。
如果在超时终止请求之后再访问 status 属性,就会导致错误。因此,将相关的代码封装到 try-catch 语句中。

overrideMimeType() 方法:重写 XHR 响应的 MIME 类型。

var xhr = createXHR();
xhr.open('get', 'text.php', true);
xhr.overrideMimeType('text/xml');
xhr.send(null);

进度事件

进度事件包括以下6个:

  • loadstart: 在接收到响应数据的第一个字节时触发
  • progress: 在接收响应期间持续不断地触发
  • error: 在请求发生错误时触发
  • abort: 在因为调用 abort() 方法而终止连接时触发
  • load: 在接收到完整的响应数据时触发
  • loadend: 在通信完成或者触发 error、abort 或 load 事件之后触发

每个请求都从触发 loadstart 事件开始,接下来是一个或多个 progress 事件,然后触发 error、abort 或者 load 事件中的一个,最后以触发 loadend 事件结束。

load 事件:响应接收完毕后将触发 load 事件,因此就没有必要再去检查 readyState 属性了。

progress 事件:progress 事件会在浏览器接收新数据的过程中周期性地被触发。

var xhr = createXHR();
xhr.onload = function(){
    if( (xhr.status >=200 && xhr.status < 300) || xhr.status ==304 ){
        console.log(xhr.responseText);
    }
    else{
        console.log('fail, ' + xhr.status);
    }
}
xhr.onprogress = function(event){
    var statusDiv = document.getElementById('status');
    if( event.lengthComputable ){
        statusDiv.innerHTML = 'Received ' + event.position + ' of ' + event.totalSize + ' bytes';
    }
}
xhr.open('get', 'progress.php', true);
xhr.send(null);

onprogress 事件处理程序,会接收到一个event对象,其 target 属性是 XHR 对象。
event 对象还包含了另外3个额外属性:lengthComputable、position、totalSize。

  • lengthComputable 是一个布尔值,它表示进度信息是否可用;
  • position 表示已经接收的字节数;
  • totalSize 表示根据 Content-Length 响应头确定的预期字节数。

跨域资源共享

CORS(Cross-Origin Resource Sharing,跨域资源共享):使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是应该失败。IE中要使用XDR对象实现,其他浏览器XHR对象原生支持。

// 发送请求附加 Origin 头部
Origin: http://www.wshunli.com
// 响应请求
Access-Control-Allow-Origin: http://www.wshunli.com

图像 Ping:动态创建图像经常用于图像 Ping 。

var img = new Image();
img.onload = img.onerror = function(){
    console.log('Done');
}
img.src = 'http://www.wshunli.com/test?action=click';

我们可以动态地创建图像,使用它们的 onload 和 onerror 事件处理程序来确定是否接收到了响应。

JSOUP:(JSON with padding,填充式 JSON 或参数式 JSON) 它看起来与 JSON 非常相似,只不过是被包含在函数调用中的 JSON。

function handleResponse(response){
    console.log("You're at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

Comet: 一种服务器向页面推送数据的技术。

实现Comet有 2 种方式: 长轮询和流。
1.长轮询是相对于传统轮询(短轮询)而言的,传统轮询即浏览器定时向服务器发送请求,查看是否有数据更新。
而长轮询则是,页面向服务器发起一个请求后,服务器一直保持连接打开,直到有数据可以发送。
发送完数据后,浏览器关闭连接,随即又向服务器发起一个新的请求。
这一过程在页面打开期间一直持续不断。
2.另外一种实现 Comet 的方式就是HTTP流。流的特点是,在页面的整个生命周期内只有使用一个HTTP连接。
也就是说,浏览器向服务器发送一个请求后,服务器保持连接打开,然后周期性地向浏览器发送数据

服务器发送事件:SSE(Server-Sent Events)服务器发送事件,是围绕只读 Comet 交互推出的 API 或者模式。

Web Sockets:Web Sockets 的目标是在一个单独的持久连接上提供全双工、双向通信。

创建 Web Sockets,可以先实例一个 WebSocket 对象并传入要连接 URL:

var socket = new WebSocket('ws://www.wshunli.com/socket.php');

实例化 WebSocket 对象之后,浏览器就会马上尝试创建连接。与 XHR 类似,WebSocket也有一个表示当前状态的 readyState 属性。

  • WebSocket.OPENING (0) : 正在建立连接
  • WebSocket.OPEN (1): 已经建立连接
  • WebSocket.CLOSING (2): 正在关闭连接
  • WebSocket.CLOSE (3): 已经关闭连接

WebSocket 没有 readystatechange 事件,readyState 的值永远从0开始。
要关闭 Web Socket 连接,可以在任何时候调用close()方法。
调用该方法后,readyState 的值立即变为2(正在关闭),当成功关闭连接后变为3。

socket.close();

发送和接收数据:Web Socket 打开之后就可以通过连接发送和接收数据。

var socket = new WebSocket('ws://www.wshunli.com/socket.php');
socket.send("Hello World!");

Web Socket 只能通过连接发送纯文本数据,对于复杂数据必须进行序列化。

socket.onmessage = function(event){
    var data = event.data;
}

当服务器向客户端发来消息时,WebSocket 对象就会触发 message 事件。

WebSocket 对象的其他事件:
WebSocket对象还有其他3个事件,在连接生命周期的不同阶段触发。

  • open: 在成功建立连接时触发
  • error: 在发生错误时触发,连接不能持续
  • close: 在连接关闭时触发
var socket = new WebSocket('ws://www.wshunli.com/server.php');
socket.onopen = function(){
    console.log('WebSocket Opened.')
}
socket.onerror = function(){
    console.log('WebSocket Error.')
}
socket.onclose = function(){
    console.log('WebSocket Closed.')
}

其中只有 close 事件的event的对象有额外的信息。这个事件的事件对象有3个额外属性: wasClean、code 和 reason。
其中,wasClean 是一个布尔值,表示连接是否已经明确关闭;code 是服务器返回的数值状态码;而 reason 是一个字符串,包含服务器发回的信息。

socket.onclose = function(event){
    console.log(event.wasClean + ',' + event.code + ',' + event.reason);
}

如果本文对您有所帮助,且您手头还很宽裕,欢迎打赏赞助我,以支付网站服务器和域名费用。 https://paypal.me/wshunli 您的鼓励与支持是我更新的最大动力,我会铭记于心,倾于博客。
本文链接:https://www.wshunli.com/posts/4d143b68.html