# 惰性函数

# 定义

我们都使用过缓存,也就是拿 if 来判断,如果存在就直接返回,否则就进行计算。

但是惰性函数,是它的加强版,但是它的使用范围偏小,当我们确定它只有一中特性的时候,我们使用惰性函数,不用判断,也不会更改。

# 第一版

function square(num) {
    return Math.sqrt(num)
}
foo(4);
foo(5);
每一次都会进行计算的。

我们来使用缓存我们可以给它缓存起来, 下次访问的时候直接返回就好.
var cache = {};
function square(num) {
    if (!cache[num]) {
        cache[num] = num * num;
    }
    return cache[num];
}

# 第二版 (闭包)

上面这种变量直接暴露在了全局下,我们利用闭包。

var square = (function () {
    var cache = {};
    return function (num) {
        if (!cache[num]) {
            cache[num] = num * num; 
        }
        return cache[num];
    }
})()

square(5); //  25
square(4); // 16

或者我们使用函数(函数对象), 可以将函数当成对象.
function square(num) {
    foo.cache = {};
    if (!foo.cache[num]) {
        cache[num] = num * num; 
    }
    return cache[num];
}
square(5); // 25
square(4); // 16

# 第三版

我们可以看出来,square调用 ,依然要每次都进行 if / else 判断,而真正的惰性函数只会走一次判断。

var square = function (num) {
    var cache = {};
    cache[num] = num * num;
    square = function () {
        return cache[num];
    }
    return square();
}

square(5); // 25
square(4); // 25
利用js弱类型语言的特点,重写变量 square。num 也至此变成了 5. 

为什么拿这个例子来讲,是为了让你感觉惰性函数和单纯缓存的特点,如果我们真的在对象下面保存了一个很耗时的对象,我们这么来可以,之后再也不会改变了。但是如果是一个计算的函数,这样将永远变为一个计算值,划不来。

# 应用 (单例模式)

function Singleton() {
    this.data = 'singleton';
}
Singleton.getInstance = (function () {
    var instance;
    return function () {
        if (instance) {
            return instance;
        } else {
            instance = new Singleton();
            return instance;
        }
    }
})();

var s1 = Singleton.getInstance();
var s2 = Singleton.getInstance();
s1 === s2; // true;


// 改掉 if
function Singleton() {
    this.data = 'singleton';
}
Singleton.getInstance = function () {
    var instance;
    instance = new Singleton();
    Singleton.getInstance = function () {
        return instance;
    }
    return Singleton.getInstance();
}
var s1 = Singleton.getInstance();
var s2 = Singleton.getInstance();
s1 === s2;  // true


# DOM 事件

为了兼容现代浏览器和 IE 浏览器,我们需要对浏览器环境进行一次判断。其实,只要我们检测过一次,就能够确定下来了。

function addEvent(type, el, fn) {
    if (window.addEventListener) {
        el.addEventListener(type, fn, false);
    } else if (window.attachEvent) {
        el.attachEvent('on' + type, fn);
    }
}

我们可以这样写
function addEvent(type, el, fn) {
    if (window.addEventListener) {
        addEvent = function (type, el, fn) {
            el.addEventListener(type, fn, false);
        }
    } else if (window.attachEvent) {
        addEvent = function (type, el, fn) {
            el.attachEvent('on' + type, fn);
        }
    }
}

我们也可以使用闭包
var addEvent = (function () {
    if (window.addEventListener) {
        return function (type, el, fn) {
            el.addEventListener(type, fn, false);
        }
    } else if (window.attachEvent) {
        return function (type, el, fn) {
            el.attachEvent('on' + type, fn);
        }
    }
})()

# 总结

如果我们想要缓存结果,并且我们不想要每次都判断,一次就再也不会更改,就可以使用惰性函数。