第20章,JSON
JSON(JavaScript Object Notation,JavaScript對象表示法),是JavaScript的一個嚴格的子集。
JSON可表示一下三種類型值:
簡單值:字符串,數值,布爾值,null,不支持js特殊值:undefined
對象:一組無序的鍵值對
數組:一組有序的值的列表
不支持變量,函數或對象實例
注:JSON的字符串必須使用雙引號,這是與JavaScript字符串最大的區別
對象
{ "name":"Nicholas", "age":20 }
注:JSON中的對象要求給屬性加引號
與JavaScript不同,沒有聲明變量,末尾不用分號
對象嵌入:
{ "name":"Nicholas", "age":19, "school":{ "name":"school", "location":"location" } }
數組
采用js的數組字面量形式:
[21,"hi",true]
注:JSON數組也沒有分號和變量
數組嵌入
[ { "title":"array", "author":"author" }, [ "title":"book", "author":{ "nameOne", "nameTwo" } ] ]
JSON對象
早期的JSON解析器基本上使用的是js的eval函數。ECMAScript5定義了全局對象JSON,支持的瀏覽器:IE8+,Firefox3.5+,Safari4+,Chrome,Opera10.5+。
JSON對象的兩個方法:stringify,parse。最簡單情況,分別用於把js對象序列化為JSON字符串和把JSON字符串解析成原生js值
var book = { title:"title", author:[ "Nicholas C. Zakas" ], edition:3, year:2011 }; var jsonText = JSON.stringify(book); alert(jsonText); //{"title":"title","author":["Nicholas C. Zakas"],"edition":3,"year":2011}
注:默認情況下JSON.stringify輸出的JSON字符串不包含任何空格字符或縮進。
序列化時所有函數和原型成員都會被忽略,值為undefined的屬性也會被跳過。
JSON.parse過程相反,傳遞的字符串不是有效JSON,會拋出錯誤
序列化選項
JSON.stringify還可以接收另外兩個參數:1、過濾器,可以是數組,也可以是函數。2、選項,表示是否在JSON字符串保留縮進
1、過濾結果
若過濾器是數組,則JSON.stringify結果將只包含數組列出的元素
var book = { title:"title", author:[ "Nicholas C. Zakas" ], edition:3, year:2011 }; var jsonText = JSON.stringify(book,["title","edition"]); //{"title":"title","edition":3}
如果是函數,則又有不同
var jsonText = JSON.stringify(book,function(key,value){ switch(key){ case "author": return value.join(","); case "year": return 5000; case "edition": return undefined; default: return value; } }); //{"title":"title","author":"Nicholas C. Zakas","year":5000}
2、字符串縮進
JSON.stringify第三個參數用於控制縮進和空白符,若是數值,表示每個級別的縮進空格數
var jsonText = JSON.stringify(book,null,4); //結果: { "title": "title", "author": [ "Nicholas C. Zakas" ], "edition": 3, "year": 2011 }
注:最大縮進空格數為10,大於10的數值全部轉為10
若縮進參數是字符串,則將被用於縮進字符
{ - -"title": "title", - -"author": [ - - - -"Nicholas C. Zakas" - -], - -"edition": 3, - -"year": 2011 }
注:最大縮進字符數不能超過10,超過的將只顯示前10個字符
3、toJSON方法
toJSON方法可以作為函數過濾器的補充,理解序列化順序:
1、如果存在toJSON方法,而且能通過它取得有效值,調用該方法,否則返回對象本身
2、若提供了第二個參數,應用這個函數過濾器,傳入函數過濾器的值是第一步返回值
3、對第二步返回值進行序列化
4、若提供了第三個參數,執行相應格式化
解析選項
JSON.parse也接收另一個參數,是一個函數,將在每個鍵值對上調用。若返回結果為undefined,表示刪除該值,返回其他值,則將該值插入到結果。
var book = { title:"title", author:[ "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; } }); alert(bookCopy.releaseDate.getFullYear()); //2011
第21章,Ajax和Comet
Ajax核心是XMLHttpRequest對象,能夠以異步的方式從服務器獲取更多信息,意味着用戶單擊后,可以不必刷新頁面也能取得數據
XMLHttpRequest
IE7+,Firefox,Opera,Chrome,Safari都支持原生的XHR對象,創建對象:
var xhr = new XMLHttpRequest();
瀏覽器兼容
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"],i,len; for(i=0,len=versions.length;i < len;i++){ try{ new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; }catch(ex){ //跳過 } } } return new ActiveXObject(arguments.callee.activeXString); }else{ throw new Error("No XHR Object available"); } } //使用示例 var xhr = createXHR();
XHR用法
第一個方法:open,接收3個參數:
1、要發送的請求的類型(“get”,“post”)
2、請求的URL
3、表示是否異步發送請求的布爾值
xhr.open("get","example.php",false);
說明:1、url相對於執行代碼的當前頁面(也可以使用絕對路徑),2、並不會真正發送請求,而是啟動一個請求以備發送
使用send方法發送:
xhr.send(null);
send接受一個參數:作為請求主體發送的數據,不需要則要傳入null。響應的數據會被填充到XHR對象的屬性。屬性簡介:
responseText:作為響應主體被返回的文本
responseXML:響應內容類型若是"text/xml"或"application/xml",將保存包含着響應數據的XML DOM文檔
status:響應的HTTP狀態
statusText:HTTP狀態說明
接到響應后,首先檢查status屬性,可以將HTTP狀態碼200,作為成功的標志,狀態碼304表示請求資源並沒有修改,可以直接使用瀏覽器中緩存的版本。
xhr.open("get","example.php",false); //同步請求 xhr.send(null); if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.resopnseText); }else{ alert("Request was unsuccessful: "+xhr.status); }
異步請求,檢查readyState屬性,表示請求/響應過程的當前活動階段,取值:
0:未初始化,尚未調用open
1:啟動,已調用open,未調用send
2:發送,已調用send,未收到響應
3:接收,已接收部分數據
4:完成,接收全部數據,已經可以在客戶端使用了
必須在調用open之前指定onreadystatechange事件處理程序才能確保跨瀏覽器兼容性:
var xhr = createXHR(); xhr.onreadystatechange = function(){ //DOM0級方法,不是所有瀏覽器都支持DOM2級方法 if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.resopnseText); }else{ alert("Request was unsuccessful: "+xhr.status); } } }; xhr.open("get","example.php",true); //異步請求 xhr.send(null);
在接收到響應之前還可以調用abort方法來取消異步請求:
xhr.abort();
HTTP頭部信息
默認情況下,發送XHR請求的同時,還會發送下列頭部信息
Accept:瀏覽器能夠處理的內容類型
Accept:瀏覽器能夠處理的內容類型
Accept-Charset:瀏覽器能夠顯示的字符集
Accept-Encoding:瀏覽器能夠處理的壓縮編碼
Accept-Language:瀏覽器當前設置語言
Connection:瀏覽器與服務器之間的鏈接類型
Cookie:當前頁面設置的熱河Cookie
Host:發出請求的頁面所在的域
Referer:發出請求的頁面的URI。注:HTTP規范把這個頭部字段拼錯了,應該是referrer
User-Agent:瀏覽器的用戶代理字符串
以上列出的基本上是所有瀏覽器都會發送的。可以通過setRequestHeader方法設置自定義的請求頭部信息。接收兩個參數:頭部字段名稱,頭部字段值,要成功發送請求頭部信息,必須在調用open方法之后,調用send方法之前調用setRequestHeader
var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.resopnseText); }else{ alert("Request was unsuccessful: "+xhr.status); } } }; xhr.open("get","example.php",true); xhr.setRequestHeader("MyHeader","MyValue"); xhr.send(null);
調用XHR對象的getRequestHeader方法並傳入頭部字段名稱,可以取得相應頭部信息,調用getAllResponseHeaders()方法則可以獲得一個包含所有頭部信息的長字符串。
GET請求
使用GET請求經常發生的一個錯誤,就是查詢字符串的格式有問題,查詢字符串的每個參數的名稱和值都必須使用
encodeURIComponent()(第五章提到的通用資源標識符編碼)進行編碼,然后才能放到URL末尾,而且所有鍵-值對都必須使用和號(&)分隔。
POST請求
通常用於向服務器發送應該保存的數據,應該把數據作為請求的主體提交,可以包含非常多的數據,且格式不限。
若需要將頁面中的表單數據進行序列化,然后通過XHR放到服務器,則可以使用14章的serialize函數來創建字符串:
function submitData(){ var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.resopnseText); }else{ alert("Request was unsuccessful: "+xhr.status); } } }; xhr.open("post","postExample.php",true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var form = document.getElementById("user-info"); xhr.send(serialize(form)); }
示例php文件:
<?php header("Content-Type:text/plain"); echo <<<EOF Name:{$_POST['user-name']} Email:{$_POST['user-email']} EOF; ?>
如不設置Content-Type頭部信息,要訪問同樣信息必須借助$HTTP_RAW_POST_DATA
XMLHttpRequest2級
定義FormData類型,為序列化表單以及創建與表單格式相同的數據(用於通過XHR傳輸)提供了便利。
方法1、
var data = new FormData(); data.append("name","Nicholas"); //接收兩個參數:鍵,值
方法2、
var data = new FormData(document.forms[0]); //直接使用表單元素
方法3、
var form = document.getElementById("user-info"); xhr.send(new FormData(form));
支持的瀏覽器:Firefox4+,Safari5+,Chrome,Android3+,WebKit
超時設定
IE8為XHR添加了timeout屬性,表示請求等待多少毫秒之后終止,在寫作JavaScript高級程序設計第三版時,IE8+仍然是唯一支持超時設定的瀏覽器
overrideMimeType方法
Firefox最早引入overrideMimeType方法,用於重寫XHR響應的MIME類型。因為返回響應的MIME類型決定了XHR如何處理它。
支持的瀏覽器Firefox,Safari4+,Opera10.5,Chrome
進度事件
Progress Events規范是W3C的一個工作草案,定義了與客戶端服務器通信有關的事件,最早針對XHR操作,目前也被其他API借鑒,6個進度事件:
loadstart:接收到響應數據第一個字節觸發
progress:接收響應期間持續不斷地觸發
error:請求錯誤觸發
abort:調用abort方法觸發
load:接收到完整的響應數據觸發
loadend:通信完成或觸發error,abort,load事件后觸發
跨源資源共享
IE對CORS的支持
CORS(Cross-Origin Resource Sharing,跨源資源共享)是W3C的一個工作草案
IE8中引入了XDR(XDomainRequest)類型,與XHR類似,但能實現安全可靠的跨域通信。與XHR不同:
1、cookie不會隨請求發送,也不會隨請求返回
2、只能設置頭部信息中的Content-Type
3、不能訪問響應頭部信息
4、只支持GET和POST請求
使用方法,也是創建一個XDomainRequest實例,調用open,調用send,open方法只接受兩個參數,請求類型,URL。所有請求都是異步。
其他瀏覽器對CORS的支持
Firefox3.5+,Safari4+,Chrome,ios版Safari,Android平台中的WebKit都通過XHR對象實現了對CORS的原生支持。
限制:
1、不能使用setRequestHeader
2、不能發送和接收cookie
3、調用getAllResponseHeaders會返回空字符串
其他跨域技術
圖像ping
JSONP
Comet
Comet一種更高級的Ajax技術。Ajax是從頁面向服務器請求數據的技術,Comet是服務器向頁面推送數據的技術。能夠讓信息近乎實時的被推送到頁面上。
服務器發送事件
SSE(Server-Sent Events,服務器發送事件)是圍繞只讀Comet交互推出的API或者模式
Web Socket
使用標准的HTTP服務器無法實現Web Socket,只有支持這種協議的專門服務器才能工作。
支持瀏覽器:Firefox6+,Safari5+,Chrome,ios4+版Safari
1、Web Socket API
要創建Web Socket,先實例一個WebSocket對象並傳入要連接的URL
var socket = new WebSocket("ws://www.example.com/server.php");
注:必須傳入絕對URL
表示當前狀態的readyState屬性:
WebSocket.OPENING(0):正在建立連接
WebSocket.OPEN(1):已建立連接
WebSocket.CLOSING(1):正在關閉連接
WebSocket.CLOSE(3):已關閉
關閉Web Socket連接:
socket.close();
2、發送和接收數據
socket.send("hello world"); //任意字符串
只能發送純文本數據,發雜結構的數據要經過序列化。
3、其他事件
open:成功建立連接觸發
error:發生錯誤觸發,連接不能持續
close:連接關閉觸發
第23章,離線應用與客戶端存儲
離線檢測
H5定義了navigator.onLine屬性,true表示能上網。
H5還定義了兩個事件:online(離線變在線觸發),offline(在線變離線觸發),在window對象上觸發。
應用緩存
要在緩存中保存數據,可以使用描述文件
數據存儲
HTTP Cookie,通常叫做cookie。
1、限制
在性質上是綁定在特定域名下的。
2、cookie的構成
cookie由瀏覽器保存的以下幾塊信息構成
名稱:唯一確定cookie的名稱,不缺分大小寫,實踐中最好看成區分大小寫。
值:儲存在cookie中的字符串值,必須被URI編碼
域:對於哪個域有效
路徑:對於域中的那個路徑,應該向服務器發送cookie
失效時間:cookie應該被刪除的時間
安全標志:指定后,cookie只有在使用ssl連接時才發送到服務器
3、js中的cookie
在js中處理cookie有些復雜,因為眾所周知的蹩腳的接口,即BOM的document.cookie屬性
基本的cookie操作:讀,寫,刪,在CookieUtil對象表示:
var socket = new WebSocket("ws://www.example.com/server.php"); var CookieUtil = { get:function(name){ var cookieName = encodeURIComponent(name) + "=" , cookieStart = document.cookie.indexOf(cookieName), cookieValue = null; if(cookieStart > -1){ var cookieEnd = document.cookie.indexOf(";",cookieStart); if(cookieEnd == -1){ cookieEnd = document.cookie.length; } cookieValue = decodeURIComponent(document.cookie.substring(cookieStart+cookieName.length,cookieEnd)); } return cookieValue; }, set:function(name,value,expires,path,domain,secure){ var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value); if(expires instanceof Date){ cookieText += "; expires=" + expires.toGMTString(); } if(path){ cookieText += "; path=" + path; } if(domain){ cookieText =+ "; domain=" + domain; } if(secure){ cookieText += "; secure=" + secure; } document.cookie = cookieText; }, unset:function(name,path,domain,secure){ this.set(name,"",new Date(0),path,domain,secure); } };
使用示例:
//設置cookie CookieUtil.set("name","Nicholas"); CookieUtil.set("book","Professional JavaScript"); //讀取 alert(CookieUtil.get("name")); //"Nicholas" alert(CookieUtil.get("book")); //Professional JavaScript //刪除 CookieUtil.unset("name"); CookieUtil.unset("book"); //設置cookie,包括它的路徑、域、失效日期 CookieUtil.set("name","Nicholas","/books/projs","www.wrox.com",new Date("January 1,2010")); //刪除剛設置的cookie CookieUtil.unset("name","/books/projs","www.wrox.com"); //設置安全cookie CookieUtil.set("name","Nicholas",null,null,null,true);
4、子cookie
為了繞開瀏覽器的單域名下cookie數量限制
5、關於cookie的思考
盡量少存儲信息,不存敏感信息
Web存儲機制
Web Storage目的是克服由cookie帶來的一些限制。主要目的:
1、提供一種cookie之外存儲會話數據的途徑;
2、提供一種存儲大量可以跨會話存在的數據的機制
Web Storage包含了兩種對象定義:sessionStorage,globalStorage,支持瀏覽器:IE8+,Firefox3.5+,Chrome4+,Opera10.5+
1、Storage類型
注:Storage類型只能存字符串,不是字符串的會被轉換成字符串
2、sessionStorage對象
數據值保存到瀏覽器關閉
3、globalStorage對象
目的:跨越會話存儲數據,有特定的訪問限制。
數據保留到js刪除或用戶清除瀏覽器緩存
4、localStorage對象
要訪問同一個localStorage對象,頁面必須來自同一域名(子域名無效),使用同一種協議,在同一個端口
數據保留到js刪除或用戶清除瀏覽器緩存
5、storage事件
對Storage對象的任何修改,都會在文檔上觸發storage事件
IndexedDB
在瀏覽器中保存結構化數據的一種數據庫
操作完全異步
1、數據庫
open方法,存在就打開,不存在就創建並打開
2、對象存儲空間
3、事務
4、使用游標查詢
在對象存儲空間調用openCursor方法卡創建游標
5、鍵范圍
通過游標查找方式有限,鍵范圍為游標增添了靈活性
6、設定游標方向
7、索引
8、並發問題
9、限制
與Web Storage類似,只能由同源(同協議,域名,端口)頁面操作,不能跨域共享信息。
空間限制