惰性载入函数和分支函数是 JS 高阶函数的两种具体应用场景,它们都是将函数作为返回值 return 到函数外部。
惰性载入就是当第 1 次根据条件执行函数后,第 2 次调用函数时,就不再检测条件,直接执行函数。
由于浏览器之间的行为差异,很多脚本会包含大量的条件检测,通过条件决定不同行为的浏览器执行不同的代码。
在注册事件处理函数时,经常需要考虑浏览器的事件模型。先要检测当前浏览器是 DOM 模型,还是 IE 的事件模型,然后调用不同的方法进行注册。
var addEvent = function (element, type, handle) {
if (element.addEventListener) {
element.addEventListener(type, handle, false);
} else {
element.attachEvent("on" + type, handle);
}
}
addEvent(document, "mousemove", function () {
console.log("移动鼠标:" + ((this.n) ? (++this.n) : (this.n = 1)));
})
addEvent(window, "resize", function () {
console.log("改变窗口大小:"+ ((this.n) ? (++this.n) : (this.n = 1)));
})
如此简单的条件检测,如果在高频、巨量的操作中,每次调用 addEvent() 方法都需要做一次条件检测,无疑是不经济的。下面使用惰性载入方法,重写 addEvent() 函数。
var addEvent = function (element, type, handle) {
//先检测浏览器,然后把合适的操作函数覆盖掉当前addEvent()
addEvent = element.addEventListener ? function (element, type, handle) {
element.addEventListener(type, handle, false);
} : function (element, type, handle) {
element.attachEvent("on" + type, handle);
};
//在第一次执行addEvent函数时,修改了addEvent函数之后,必须执行一次
addEvent(element, type, handle);
}
在上面代码中,当第 1 次调用 addEvent() 函数时做一次条件检测;然后根据浏览器选择相应的事件注册方法,同时把这个操作封装在一个匿名函数中;接着使用该函数覆盖掉 addEvent() 函数;最后执行第 1 次事件注册操作。这样,当第 2 次开始再次注册事件时,就不需要做条件检测了。
分支函数与惰性载入函数都是解决条件检测的问题。分支函数类似面向对象编程的接口,对外提供相同的操作接口,内部实现则会根据不同的条件执行不同的操作。分支函数与惰性载入函数在设计原理上是非常相近的,只是在代码实现方面略有差异。
使用分支函数解决浏览器兼容性的重复判断。解决浏览器兼容性的一般方法是使用 if 语句进行特性检测或能力检测,然后根据浏览器的不同,实现功能上的兼容。这样做的问题是,每执行一次代码,可能都需要进行一次浏览器兼容性方面的检测,这是没有必要的。
分支函数的设计思路:在代码初始化执行的时候检测浏览器的兼容性,在之后的代码执行过程中,就不再进行检测。
下面声明一个 XMLHttpRequest 实例对象。
var XHR = function () {
var standard = {
createXHR : function () {
return new XMLHttpRequest();
}
}
var newActionXObject = {
createXHR : function () {
return new ActionXObject("Msxml2.XMLHTTP");
}
}
var oldActionXObject = {
createXHR : function () {
return new ActionXObject("Microsoft.XMLHTTP");
}
}
if (standard.createXHR) {
return standard;
} else {
try {
newActionXObject.createXHR();
return newActionXObject;
} catch {
oldActionXObject.createXHR();
return oldActionXObject;
}
}
} ();
var xhr = XHR.createXHR(); //创建XMLHttpRequest实例对象
在代码初始化执行之后,XHR 被初始化为一个对象,拥有 createXHR() 方法,该方法的实现已经在初始化阶段根据当前浏览器选择了合适的方法,当调用 XHR.createXHR() 方法创建 XMLHttpRequest 实例对象时,就不再去检测浏览器的兼容性问题。