第二十二章
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、 解耦