转自 西红柿不是番茄
Lazy Definition Pattern是这样的一个模式:根据浏览器之间的解析javascript的差异性,使得创建封装的对象或者是函数的时候都需要使用浏览器的嗅探技术来做判断,而且对象或者方法每调用一次就需要去嗅探,这是一个非常不好的额外功。而解决这个瓶颈的方法之一就是Lazy Definition了。它会在浏览器第一次执行该对象或者函数的时候就记住这次的操作,以至于下面的重复调用不会再去执行浏览器的嗅探。让我们先从一个简单的addListener封装函数来一步步分析。
我们通常封装浏览器的添加事件函数的方式是使用下面的方式:
var addListener=function(el, type, handle) {
if (el.addEventListener) {
el.addEventListener(type, handle, false);
}else if (el.attachEvent) {
el.attachEvent('on' + type, handle);
} else {
el['on' + type] = handle;
}
}
if (el.addEventListener) {
el.addEventListener(type, handle, false);
}else if (el.attachEvent) {
el.attachEvent('on' + type, handle);
} else {
el['on' + type] = handle;
}
}
上面是一种使用很普遍的封装方式,它的问题之一就是口头说的,每次addListener函数调用的时候,都需要去执行if判断,以至于使用正确的方式,讨厌的if的执行次数跟调用次数相同了,不爽!
为了解决上面讨厌的if的反复执行,我们使用Lazy Definition来改造addListener方法:
var addListener = function(el, type, handle){
if (el.addEventListener) {
//重新定义addListener的方法体,使得下次调用addListener方法的时候就直接调用这个方法体,下同
addListener = function(el, type, handle){
el.addEventListener(type, handle, false);
}
} else
if (el.attachEvent) {
addListener = function(el, type, handle){
el.attachEvent("on" + type, function(e){
handle.call(el, e);
});
}
} else {
addListener = function(el, type, handle){
el["on" + type] = handle;
}
}
//第一次执行addListener方法
addListener(el, type, handle);
}
if (el.addEventListener) {
//重新定义addListener的方法体,使得下次调用addListener方法的时候就直接调用这个方法体,下同
addListener = function(el, type, handle){
el.addEventListener(type, handle, false);
}
} else
if (el.attachEvent) {
addListener = function(el, type, handle){
el.attachEvent("on" + type, function(e){
handle.call(el, e);
});
}
} else {
addListener = function(el, type, handle){
el["on" + type] = handle;
}
}
//第一次执行addListener方法
addListener(el, type, handle);
}
上面的addListener定义方式是YAHOO提出的一种Lazy Definition方式,它还有一种变体,我把它改成如下的方式(有点类似于分支技术):
var addListener = function(el, type, handle){
//在这里也是重新定义addListener方法
addListener = (function(){
if (el.addEventListener) {
return function(el, type, handle){
el.addEventListener(type, handle, false);
};
} else if (el.attachEvent) {
return function(el, type, handle){
el.attachEvent("on" + type, function(e){
handle.call(el, e);
});
};
} else {
return function(el, type, handle){
el["on" + type] = handle;
};
}
})();
addListener(el, type, handle);
}
//在这里也是重新定义addListener方法
addListener = (function(){
if (el.addEventListener) {
return function(el, type, handle){
el.addEventListener(type, handle, false);
};
} else if (el.attachEvent) {
return function(el, type, handle){
el.attachEvent("on" + type, function(e){
handle.call(el, e);
});
};
} else {
return function(el, type, handle){
el["on" + type] = handle;
};
}
})();
addListener(el, type, handle);
}
现在Lazy Definition的原理已经很清晰了:就是在函数内部重新自定义自己的方法体来实现。【测试页面】。下面再用一个简单的函数来表述:
var foo=function(){
var t=new Date();
foo=function(){
return t;
}
return foo(); //用于第一次调用的时候执行
}
var t=new Date();
foo=function(){
return t;
}
return foo(); //用于第一次调用的时候执行
}
更多资料可以阅读:《Lazy Function Definition Pattern》