函数的记忆能力

所谓memoization,即让一个函数具备一种可以记忆它历史被调用时候产生的运算结果的能力。

首先创建一个叫做memoized()的方法,实现了记住一个已经存在的函数的返回值。

在这个例子中我们并没有用到闭包

Function.prototype.memoized = function(key){
    this._values = this._values || {};
    return this._values[key] !== undefined ? 
        this._values[key] : 
        this._values[key] = this.apply(this, arguments); 
};

function isPrime( num ){ 
    var prime = num != 1; 
    for ( var i = 2; i < num; i++) { 
        if (num % i == 0){ 
            prime = false; break; 
        } 
    } 
    return prime; 
};

alert(isPrime.memoized(5));
alert(isPrime._values[5]);

在上面这个例子中,结果都被缓存在了_values中。
有趣的一点是,计算和存储是在一个single step中。
结果是通过.apply()来调用父函数来完成,然后直接将结果存储在了父函数的属性_values中。
所以整个事件链是这样: 计算出结果,保存结果,返回结果。所有这些都是在一个逻辑代码块中完成

这样做的缺点在于:调用isPrime()的时候还必须记得要调用.memoized()方法,来实现memoization。

如果解决这个缺点呢?

用闭包!

Function.prototype.memoized = function(key){
    this._values = this._values || {};
    xyz = this._values;

    return this._values[key] !== undefined ?
        this._values[key] : 
        this._values[key] = this.apply(this, arguments);
};

// 这里得memoize就是利用闭包的特性,来隐性的更改了ipPrime的行为
Function.prototype.memoize = function(){
    var fn = this; //#1
    return function(){ //#2 
        return fn.memoized.apply(fn, arguments); 
    };
};

var isPrime = (function ( num ){ 
    var prime = num != 1; 
    for ( var i = 2; i < num; i++) { 
        if (num % i == 0){ 
            prime = false; break; 
        } 
    } 
    return prime; 
}).memoize();

alert(isPrime(5));
alert(xyz[5]);

我们通过一点改进,完美的解决了之前的那个缺陷。

在本例中,我们创建了一个新的方法,memoize()。
在memozie()中,利用memoized()重新包裹了原始函数(original function)。
这样一来,memoize返回的函数就永远会是具备了momoized能力的函数(#2)

请注意,在momozie()这个方法中,我们构建了一个闭包, 在这个闭包中通过fn这个变量拷贝了原始函数:isPrime函数(通过获取其上下文 #1),
这是一个很通用的技巧:每个函数都拥有自己的上下文,所以上下文从来都不是闭包的一部分。
但是我们可以利用一个变量来关联原始函数的上下文的值, 这样就等同于函数上下文(isPrime context)成为了闭包的一部分。 由于原始函数已经成为了闭包的一部分,那么闭包自然可以在返回的新函数中, 随意的操作原始函数(isPrime),让其具备记忆能力。

原文地址:https://www.cnblogs.com/gongshunkai/p/6654716.html