读书笔记:javascript高级技巧(二)

时间:2023-03-10 04:58:17
读书笔记:javascript高级技巧(二)

四。惰性载入函数

因为浏览器兼容的原因,我们的javascript代码会有大量的if语句,将执行引导到正确的代码中,看如下函数:

 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];
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}

每次在调用createXHR时,都要对浏览器支持的能力进行检查。如果多次调用,这种检查就没有必要了。如果if语句不必每次执行,那么代码可以运行的更快一些。解决方案就是称之为惰性载入的技巧。
惰性载入表示函数执行的分支仅会发生一次。有两种实现惰性载入的方式。第一种就是在函数被调用时再处理函数:在第一次调用的过程中,该函数会被覆盖为另外一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行分支。第二种是在声明函数时就指定适当的函数:这样第一次调用时就不会损失性能力,而在代码首次加载时会损失一点性能。具体看码~

1.在函数被调用时再处理函数

function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
createXHR = function(){
return new
XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
createXHR = function(){
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];
} catch (ex){
//skip
}
}
} return new
ActiveXObject(arguments.callee.activeXString);
};

} else {
createXHR = function(){
throw new Error("No XHR object available."
);
};
} return createXHR();
} var xhr1 = createXHR();
var xhr2 = createXHR();

在第一次调用函数时会再处理函数,根据不同条件重写函数,这样在以后的调用中会直接调用新重写的函数而不用经过重重判断。

2.在声明函数时就指定适当的函数

 var createXHR = (function(){
if (typeof XMLHttpRequest != "undefined"){
return function(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
return function(){
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){
//skip
}
}
} return new ActiveXObject(arguments.callee.activeXString);
};
} else {
return function(){
throw new Error("No XHR object available.");
};
}
})(); var xhr1 = createXHR();
var xhr2 = createXHR();
 //自执行匿名函数语法:(function(){})()  最开始看不懂这高大上的写法,原来是自执行函数~~~

这种方式类似于第一种,思路水样的,不同的就是第一行代码,新增了自执行的匿名函数,另外每个分支都返回正确的函数定义,以便立即将其复制给createXHR()。

五。函数柯里化

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家哈斯凯尔·加里命名的,尽管它是 Moses Schönfinkel 和 Gottlob Frege 发明的。

这是来自*的名词解释。顾名思义,柯里化其实本身是固定一个可以预期的参数,并返回一个特定的函数,处理批特定的需求。这增加了函数的适用性,但同时也降低了函数的适用范围。

理解起来比较困难,下面看实例:

function curry(fn){
var args = Array.prototype.slice.call(arguments, 1); //获取第一个参数之后的所有参数
return function(){
var innerArgs = Array.prototype.slice.call(arguments), //获取内部函数的所有参数
finalArgs = args.concat(innerArgs); //组合
return fn.apply(null, finalArgs); //没有考虑到执行环境,所以apply()第一个参数为null
};
} function add(num1, num2){
return num1 + num2;
} var curriedAdd = curry(add, 5); //创建了第一个参数绑定为5的柯里化版本
alert(curriedAdd(3)); //8 //传入第二个参数,调用add方法,相当于add(5,3) var curriedAdd2 = curry(add, 5, 12);
alert(curriedAdd2()); //

函数柯里化还常常作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数;

function bind(fn, context){
var args = Array.prototype.slice.call(arguments, 2);
return function(){
var innerArgs = Array.prototype.slice.call(arguments),
finalArgs = args.concat(innerArgs);
return fn.apply(context, finalArgs);
};
} var handler = {
message: "Event handled", handleClick: function(name, event){
alert(this.message + ":" + name + ":" + event.type);
}
}; var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));