概念

惰性函数,表示函数执行的分支只会在函数第一次调用的时候执行。在一次调用过程中,该函数会被覆盖威另一个按照合适方式执行的函数。这样对原函数的调用就不会再经过执行的分支了。

简单的来说,就是可以记录第一次的操作,之后就不再走第一次的老路了,而是采用一种获取值的方式。

应用案例1.

如果有一个函数,在函数里就行一个求值操作(纯函数),不会有副作用的情况下,我们为了将第一次的值保存下来,之后就不需要求得一遍,直接拿缓存

var cache = [ ];
function sqrt (x) {
    if ( !cache[x] ) {
        return x * x;
    }
    return cache[x];
}

我们举一个简单的例子,就可以看出来它的操作就是: 如果是第一次求 x 的平方的话,我们就乖乖的求值,只要求过一次,我们就直接拿缓存 cache 里面的值。是不是符合惰性的感觉。

我们可以发现,其实这个函数是没有复用性的,这是一个有副作用的函数,它在全局下声明了一个cache 变量。我们可以借助闭包的形式来把这个变量变为 sqrt 私有的属性。

function sqrt ( x ) {
    var cache = [ ];
    
    return function () {
        if ( !cache[x] ) {
            return x * x;
        }
        return cache[x];
    }
}

闭包是无处不在的,只要引用了外部环境的变量,(自由变量),函数在调用完成后就不会销毁了。一直会存在在你的内存当中的。

这样的函数是不是就可以很好的解决了副作用呢。

应用案例2.

单例模式,只会产生一个实例,就算 new 多次,也就是会紧紧产生一个。我们可以通过缓存的形式,只让第一次正常的 new 即可.

function SingleModel() {
    this.name = '张三';
}

SingleModel.single = (function() {
    var instance;
    
    return function () {
        if (instance) {
            return instance;
        } else {
            instance = new Person();
            return instance;
        }
    }
})();

var single1 = SingleModel.single();
var single2 = SingleModel.single();
console.log(single1 === single2); // true

我们还是使用闭包的形式,只要内层函数引入着 instance 就不会释放掉这个环境,我们就可以拿来判断,一旦不是 undefined 就说明是 new 过一次了。第二次就可以直接走存下来的。

包装器

 我们可以生一个包装器一样的函数,这个函数可以使得另一个函数的结果被缓存下来,类似缓存工具。


var wrapper = function (fn) {
    var result;
    return function () {
        return result || ( result = fn.apply(this, [].slice.call(arguments)) );
    }
}

// 使用

function foo(x) {
    return x * x;
}

var x = wrapper(foo);

x(2);

我们可以通过 wrapper 重新来包装一个对象,这个包装器可以缓存函数的结果,并且使用 apply 可以重新绑回 this 指向,不会让原本的函数 this 丢失。