《JavaScript高级程序设计》心得笔记-----第五篇章
第二十二章
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、 解耦