概念
惰性函数,表示函数执行的分支只会在函数第一次调用的时候执行。在一次调用过程中,该函数会被覆盖威另一个按照合适方式执行的函数。这样对原函数的调用就不会再经过执行的分支了。
简单的来说,就是可以记录第一次的操作,之后就不再走第一次的老路了,而是采用一种获取值的方式。
应用案例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 丢失。