javascript的疑问适用 - 功能记忆

时间:2014-03-22 14:26:06

标签: javascript memoization

我正在努力学习一本书中的js memoization示例,这是代码:

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

这是一个带有完整示例的fiddle

我真正得到的是这段代码是如何工作的以及它的作用,特别是apply部分:

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

我知道并理解apply如何运作

  

apply()方法调用一个给定此值的函数,并以数组

的形式提供参数

假设this._values[key]等于undefined,则返回的值为this.apply(this, arguments):此代码是否会重新启动memoized函数?我试图在函数中添加一些日志来查看调用函数的次数,但它似乎只启动了一次..

任何人都可以给我一个提示吗?这可能是一个虚假的问题,请耐心等待,谢谢

2 个答案:

答案 0 :(得分:2)

让我们使用一个简单的例子,斐波那契数字。

function fib(n) {
    if (n < 2) return 1;
    return fib.memoized(n-1) + fib.memoized(n-2);
}

在这里,我们可以看到memoized方法应用于fib函数,即您的this keyword引用了fib函数。它不会重新启动memoized函数,而是“启动”调用它的函数。但是,它确实将this设置为函数本身,这没有任何意义。更好:

Function.prototype.memoize = function(key){
    if (!this._values)
        this._values = {};
    if (key in this._values)
        return this._values[key];
    else
        return this._values[key] = this.apply(null, arguments);
// pass null here:                            ^^^^
}

如果memoized会返回一个闭包,那就更好了:

Function.prototype.memoized = function(v) {
    var fn = this, // the function on which "memoized" was called
        values = v || {};
    return function(key) {
        if (key in values)
            return values[key];
        else
            return values[key] = fn.apply(this, arguments);
    }
}
var fib = function(n) {
    if (n < 2) return 1;
    return fib(n-1) + fib(n-2);
}.memoized();
// or even
var fib = function(n) { return fib(n-1) + fib(n-2) }.memoized({0:1, 1:1});

答案 1 :(得分:1)

备注

  1. 由于您将memoized附加到Function.prototype,因此您只能在其他某个功能上调用此memoized。就像在你的例子中一样

    isPrime.memoized(5)
    
  2. 由于您在函数上调用memoizedthis将引用调用memoized的函数。因此,在这种情况下,this引用isPrime


  3. 实际解释

    this._values = this._values || {};
    

    这一行确保isPrime有一个名为_values的属性,并且它应该有一个空对象(如果它不存在)。

    this._values[key] !== undefined
    

    此检查是为了确保我们已经使用key调用了我们。如果值不是undefined,则返回this._values[key]

    否则,

    this._values[key] = this.apply(this, arguments)
    

    this.apply(this, arguments)中存储调用this._values[key]的结果并将其返回。现在是重要的一部分。

    this.apply(this, arguments)
    

    直截了当。 arguments是一个类似于对象的数组。所以,如果您实际上已经isPrime实际调用isPrime(1, 2, 3, 4),则参数将为{'0': 1, '1': 2, '2': 3, '3': 4}。现在我们在memoized内,我们需要调用isPrime,因为它打算被调用。所以,this.apply(this, arguments)完成了。 Function.prototype.apply,尝试在调用函数时传播数组,就像传递给第二个参数的对象一样。