先举一个例子:写一个函数,这个函数的返回值为第一次调用时的new Date().getTime()值。
首先想到的是定义一个全局变量,然后在函数中判断该变量是否有值,如果有值则直接返回;否则进行赋值。
var t = null;
function getTime() {
if (t) {
return t;
}
t = new Date().getTime();
return t;
}
console.log(getTime());//1538147528953
console.log(getTime());//1538147528953
console.log(getTime());//1538147528953
上面这种写法虽然实现了功能,但是我们存在两个问题:
1)易污染全局变量。
2)每次执行函数都需要进行判断,而我们所期望的是只在第一次执行函数的时候进行判断就可以了,后面的执行没有必要再进行判断。
全局变量的问题可以使用闭包来解决
var getTime = (function () {
var t;
return function () {
if (t) {
return t;
}
t = new Date().getTime();
return t;
}
})();
对于第二个问题,可以用函数覆盖的方式。也就是赋值之后,将原函数用新函数覆盖,而新函数直接使用赋值后的变量。
var getTime = function () {
var t = new Date().getTime();
return function () {
getTime = function () {
return t;
}
return getTime();
}
}
这种函数可以称为惰性函数:函数的判断分支只会执行一次,之后调用函数时,直接进入所支持的分支代码或使用已定义的变量。
在前端开发中,为了兼容各浏览器,经常需要编写一些含有大量if语句的兼容性的方法,每次执行此方法都需要进行一系列的判断。而使用惰性函数的写法可以减少一些性能的损耗。比如我们常用的添加事件的兼容性方法就可以使用惰性函数的方式。
function addEvent(dom, type, fn) {
if (dom.addEventListener) {
dom.addEventListener(type, fn, false);
addEvent = function (dom, type, fn) {
dom.addEventListener(type, fn, false);
}
} else if (dom.attachEvent) {
dom.attachEvent('on' + type, fn);
addEvent = function (dom, type, fn) {
dom.attachEvent('on' + type, fn);
}
} else {
dom['on' + type] = fn;
addEvent = function (dom, type, fn) {
dom['on' + type] = fn;
}
}
}