第二十二章 1、 安全的檢測是使用:Object.prototype.toString.call(value); eg: PS:JSON的: 2、 作用安全域的構造函數:(不然this會指向window) PS:使用作用安全域的構造函數,就會鎖定調用構造函數的環境,如果使用構造函數竊取模式的繼承而且 ...
第二十二章
1、 安全的檢測是使用:Object.prototype.toString.call(value);
eg:
function isArray(value){ return Object.prototype.toString.call(value) == “[object Array]”; }
PS:JSON的:
var isNativeJSON ==windoe.JSON && Object.prototype.toString.call(JSON) == “[object JSON]”;
2、 作用安全域的構造函數:(不然this會指向window)
function Person(name,age){ if(this instanceof Person){ this.name = name; this.age = age; } else{ return new Person(name,age); } }
PS:使用作用安全域的構造函數,就會鎖定調用構造函數的環境,如果使用構造函數竊取模式的繼承而且不使用原形鏈,這個繼承就有可能被破壞掉
當一個構造函數(Student)繼承一個使用作用安全域的構造函數的時候,裡面要使用Person.call(this,”ccl”,23);來繼承,但是還需要在這個函數下麵使用
Student.prototype = new Person();
3、 惰性載入函數:
1) 函數被調用時在處理函數(重寫函數)【函數名 = function(){//代碼}】
2) 在聲明函數時就指定適當的函數【return function(){//代碼}】
4、 函數綁定【創建一個函數,在特定的this環境中以指定參數調用另一個函數,通常與回調函數與事件處理程式一起使用】
var handler = { message: "Event handled", handleClick: function(event){ alert(this.message); } };
1) 自己創建bind()
(1) 創建一個bind()函數接受一個函數和一個環境,並返回給定環境中調用給定函數,並且將所有參數原封不動傳遞過去
function bind(fn,context){ return function(){ return fn.apply(context,argument); } }
(2) 調用EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));
2) 利用原生的bind()方法:EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler));
5、 函數柯里化【使用一個閉包返回一個函數】
1) 創建柯里化的通用方式
function curry(fn){ var args = Array.prototype.slice.call(arguments, 1);//1表示返回數組包含從第二個參數開始 的所有參數 return function(){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return fn.apply(null, finalArgs); }; }
調用:var curriedAdd = curry(add, 5);//這裡的add後面可以添加多個參數
2) 作為函數綁定的一部分包含在其中,創造出更複雜的bind()函數
function bind(fn, context){ var args = Array.prototype.slice.call(arguments, 2); return function(){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return fn.apply(context, finalArgs); }; }
使用:EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));
3) 利用原生的bind()方法:
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler, "my-btn"));
6、 防篡改對象(一旦把屬性把屬性定義為防篡改就無法撤銷了)
1) 不可擴展對象:Object.preventExtensions(person);
判斷是否可以擴展:Object.isExtensible (person)
2) 密封的對象【密封對象不可擴展,而且configuraable會設置為false,也就是不能刪除屬性和方法,但是屬性值是可以修改的,在非嚴格模式下,刪除和修改屬性會被忽略,但是在嚴格模式下,會拋出錯誤】
Object.seal(person);
判斷是否被密封:Object.isSealed (person)
3) 凍結對象【既不可以擴展,又是密封的,而且對象的writable被設置為false,,在非嚴格模式下,對凍結的對象執行非法操作會被忽略,但是在嚴格模式下,會拋出錯誤】
Object.Froze(person);
判斷是否被凍結:Object. isFrozen (person)
7、 高級定時器
重覆定時器:鏈式 setTimeout()調用。
setTimeout(function(){ //處理中 setTimeout(arguments.callee, interval); }, interval);
8、 Yielding Processes
1) 數組分塊
function chunk(array, process, context){ setTimeout(function(){ var item = array.shift(); process.call(context, item); if (array.length > 0){ setTimeout(arguments.callee, 100); } }, 100); }
9、 函數節流
function throttle(method, context) { clearTimeout(method.tId); method.tId= setTimeout(function(){ method.call(context); }, 100); }
10、自定義事件
function EventTarget(){ this.handlers = {}; } EventTarget.prototype = { constructor: EventTarget, addHandler: function(type, handler){ if (typeof this.handlers[type] == "undefined"){ this.handlers[type] = []; } this.handlers[type].push(handler); }, fire: function(event){ if (!event.target){ event.target = this; } if (this.handlers[event.type] instanceof Array){ var handlers = this.handlers[event.type]; for (var i=0, len=handlers.length; i < len; i++){ handlers[i](event); } } }, removeHandler: function(type, handler){ if (this.handlers[type] instanceof Array){ var handlers = this.handlers[type]; for (var i=0, len=handlers.length; i < len; i++){ if (handlers[i] === handler){ break; } } handlers.splice(i, 1); } } };
使用:
1)
function handleMessage(event){ alert("Message received: " + event.message); } //創建一個新對象 var target = new EventTarget(); //添加一個事件處理程式 target.addHandler("message", handleMessage); //觸發事件 target.fire({ type: "message", message: "Hello world!"}); //刪除事件處理程式 target.removeHandler("message", handleMessage); //再次,應沒有處理程式 target.fire({ type: "message", message: "Hello world!"});
2) 其他對象可以繼承 EventTarget 並獲得這個行為:
function Person(name, age){ EventTarget.call(this); this.name = name; this.age = age; } inheritPrototype(Person,EventTarget); Person.prototype.say = function(message){ this.fire({type: "message", message: message}); };
11、拖放:
var DragDrop = function(){ var dragdrop = new EventTarget(), dragging = null, diffX = 0, diffY = 0; function handleEvent(event){ //獲取事件和對象 event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); //確定事件類型 switch(event.type){ case "mousedown": if (target.className.indexOf("draggable") > -1){ dragging = target; diffX = event.clientX - target.offsetLeft; diffY = event.clientY - target.offsetTop; dragdrop.fire({type:"dragstart", target: dragging, x: event.clientX, y: event.clientY}); } break; case "mousemove": if (dragging !== null){ //指定位置 dragging.style.left = (event.clientX - diffX) + "px"; dragging.style.top = (event.clientY - diffY) + "px"; //觸發自定義事件 dragdrop.fire({type:"drag", target: dragging, x: event.clientX, y: event.clientY}); } break; case "mouseup": dragdrop.fire({type:"dragend", target: dragging, x: event.clientX, y: event.clientY}); dragging = null; break; } }; //公共介面 dragdrop.enable = function(){ EventUtil.addHandler(document, "mousedown", handleEvent); EventUtil.addHandler(document, "mousemove", handleEvent); EventUtil.addHandler(document, "mouseup", handleEvent); }; dragdrop.disable = function(){ EventUtil.removeHandler(document, "mousedown", handleEvent); EventUtil.removeHandler(document, "mousemove", handleEvent); EventUtil.removeHandler(document, "mouseup", handleEvent); }; return dragdrop; }();
第二十三章
1、 離線檢測:navigator.onLine【true能上網,反之,但是不同瀏覽器之間還是有些差異】
確定網路是否可用:online 和 offline
EventUtil.addHandler(window, "online", function(){ alert("Online"); }); EventUtil.addHandler(window, "offline", function(){ alert("Offline"); });
在頁面載入後,最好先通過 navigator.onLine 取得初始的狀態。然後,就是通過上述兩個事件來確定網路連接狀態是否變化
2、 應用緩存(appcache):applicationCache()對象
3、 Cookie:名稱和值都必須經過URL編碼【decodeURIComponent()來解碼】
1) 讀取、寫入、刪除
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"; } 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"); //讀取 cookie 的值 alert(CookieUtil.get("name")); //"Nicholas" alert(CookieUtil.get("book")); //"Professional JavaScript" //刪除 cookie 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);
2) 子cookie
var SubCookieUtil = { get: function (name, subName){ var subCookies = this.getAll(name); if (subCookies){ return subCookies[subName]; } else { return null; } }, getAll: function(name){ var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie.indexOf(cookieName), cookieValue = null, cookieEnd, subCookies, i, parts, result = {}; if (cookieStart > -1){ cookieEnd = document.cookie.indexOf(";", cookieStart); if (cookieEnd == -1){ cookieEnd = document.cookie.length; } cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd); if (cookieValue.length > 0){ subCookies = cookieValue.split("&"); for (i=0, len=subCookies.length; i < len; i++){ parts = subCookies[i].split("="); result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } return result; } } return null; }, //省略了更多代碼 };
使用:
//假設 document.cookie=data=name=Nicholas&book=Professional%20JavaScript //取得全部子 cookie var data = SubCookieUtil.getAll("data"); alert(data.name); //"Nicholas" alert(data.book); //"Professional JavaScript" //逐個獲取子 cookie alert(SubCookieUtil.get("data", "name")); //"Nicholas" alert(SubCookieUtil.get("data", "book")); //"Professional JavaScript"
4、 IE用戶數據
1) 使用 CSS 在某個元素上指定 userData 行為,就可以使用setAttribute()方法來保存數據:
<div style="behavior:url(#default#userData)" id="dataStore"></div> var dataStore = document.getElementById("dataStore"); dataStore.setAttribute("name", "Nicholas"); dataStore.setAttribute("book", "Professional JavaScript"); dataStore.save("BookInfo");
2) 下一次載入時,可以使用load()來獲取數據:
dataStore.load("BookInfo");
dataStore.getAttribute("name")
3) removeAttribute()方法明確指定要刪除某元素數據,只要指定屬性名稱。刪除之後,必須像下麵這樣再次調用 save()來提交更改。
dataStore.removeAttribute("name");
dataStore.save("BookInfo");
5、 Web存儲機制:
1) storage類型(只存儲字元串):
(1) clear(),刪除所有值; Firefox 中沒有實現
(2) getItem(name) 可以直接調用
(3) key(index) 獲得 index 位置處的值的名字
(4) removeItem(name) 可以直接調用
(5) setItem(name,value) 可以直接調用
(6) length值對數量,無法判斷對象中所有數據的大小,不過 IE8 提供了一個 remainingSpace 屬性,用於獲取還可以使用的存儲空間的位元組數
2) sessionStorage 對象
(1) 存儲方法:
(1st) 使用方法存儲數據
sessionStorage.setItem("name", "Nicholas");
(2nd) 使用屬性存儲數據
sessionStorage.book = "Professional JavaScript";
PS:只適用於IE8:
sessionStorage.begin(); sessionStorage.name = "Nicholas"; sessionStorage.book = "Professional JavaScript"; sessionStorage.commit();
(2) 讀取數據:
(1st) 使用方法存儲數據
var name = sessionStorage.getItem("name");
(2nd) 使用屬性存儲數據
var book = sessionStorage.book;
結合 length 屬性和 key()方法來迭代 sessionStorage 中的值:
for (var i=0, len = sessionStorage.length; i < len; i++){ var key = sessionStorage.key(i); var value = sessionStorage.getItem(key); }
(3) 使用 for-in 迴圈來迭代 sessionStorage 中的值:
for (var key in sessionStorage){ var value = sessionStorage.getItem(key); alert(key + "=" + value); }
(4) 刪除數據
(1st) 使用 delete 刪除一個值——在 WebKit 中無效
delete sessionStorage.name;
(2nd) 使用方法刪除一個值
sessionStorage.removeItem("book");
3) globalStorage 對象:
//保存數據 globalStorage["wrox.com"].name = "Nicholas"; //獲取數據 var name = globalStorage["wrox.com"].name;
PS: 事先不能確定功能變數名稱,那麼使用 location.host 作為屬性名比較安全
4) localStorage 對象:
//使用方法存儲數據 localStorage.setItem("name", "Nicholas"); //使用屬性存儲數據 localStorage.book = "Professional JavaScript"; //使用方法讀取數據 var name = localStorage.getItem("name"); //使用屬性讀取數據 var book = localStorage.book;
5) 為了相容只支持 globalStorage 的瀏覽器:
function getLocalStorage(){ if (typeof localStorage == "object"){ return localStorage; } else if (typeof globalStorage == "object"){ return globalStorage[location.host]; } else { throw new Error("Local storage not available."); } }
使用:var storage = getLocalStorage();
6) storage 事件:
(1) 屬性【IE8 和 Firefox 只實現了 domain 屬性】:
domain:發生變化的存儲空間的功能變數名稱;
key:設置或者刪除的鍵名;
newValue:如果是設置值,則是新值;如果是刪除鍵,則是 null;
- oldValue:鍵被更改之前的值;
(2) 偵聽 storage 事件:
EventUtil.addHandler(document, "storage", function(event){ alert("Storage changed for " + event.domain); });
6、 IndexedDB(資料庫,使用對象保存數據)
1) 每一次 IndexedDB 操作,都需要註冊 onerror 或 onsuccess 事件處理程式,以確保適當地處理結果
var request, database,errorInfo; if (database.version != "1.0"){ request = database.setVersion("1.0"); request.onerror = function(event){ errorInfo = event.target.errorCode;//錯誤信息 }; request.onsuccess = function(event){ database = event.target.result;//資料庫實例對象 }; } else { alert("Database already initialized. Database name: " + database.name + ", Version: " + database.version); }
第二十四章
1、 可維護性
2、 解耦
第二十五章