《JavaScript高级程序设计》心得笔记-----第五篇章

时间:2022-11-04 08:27:06

第二十二章

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、  解耦