7

JS 初学者 :) 需要对Crockford 的书第 4.15 节中的代码片段进行解释:

var memoizer = function (memo, fundamental) {
    var shell = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fundamental(shell, n);
            memo[n] = result;
        }
        return result;
    };
    return shell;
};

var fibonacci = memoizer([0, 1], function (shell, n) {
    return shell(n - 1) + shell(n - 2);
});

问题:我们如何计算斐波那契(15),如果是简单的斐波那契(15)调用,那么它如何详细工作?

感谢帮助。

4

4 回答 4

3

这是一个带console.log()注释的版本,它试图显示堆栈如何返回并将 (n-1)+(n-2) 的结果分配给每个相应递归调用的备忘录数组。还要记住堆栈以相反的顺序返回。因此,在记录的输出中,您将看到最后一个调用首先返回:

var memoizer = function (memo, fundamental) {
    var shell = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fundamental(shell, n);
            console.log("Hence 'shell(n-1)+shell(n-2)' results in the assignment memo["+n+"]="+result);
            memo[n] = result;
        }
        return result;
    };
    return shell;
};
var fibonacci = memoizer([0, 1], function (shell, n) {
    console.log("shell is called, and 'n' is equal to --> " + n + "\n" + "At this point shell(n-1)="+shell(n-1)+" AND shell(n-2)="+shell(n-2));
    return shell(n - 1) + shell(n - 2);    
});
于 2015-06-15T21:01:55.850 回答
2

看起来您对调用为何fibonacci(15)起作用感到困惑。让我们简化代码(暂时忘记记忆)。

var m = function () {
    var s = function (n) {
        console.log(n);
    };
    return s;
}; 
var f = m();

基本上我们设置f为 function 的返回值m()。在这种情况下,该返回值是一个函数。看,我们可以进一步简化为:

var f = function (n) { console.log(n); };

In other words, we are setting f to be a function that takes in one parameter. We are doing the same thing in the fibinacci example. That is why the invocation fibonacci(15) works.

于 2015-10-18T02:22:17.443 回答
1

要评估该函数,您只需调用它:

fibonacci(15);

如果您想查看结果,最简单的方法是:

alert(fibonacci(15));

如果您想更频繁地执行此操作,请下载Firebug,并在脚本底部执行此操作:

Console.log(fibonacci(15));

或者直接在 Firebug 控制台中输入,然后按回车键:

fibonacci(15)
于 2010-09-26T17:11:40.323 回答
1

正如对您问题的评论所建议的那样,如果您无法按照书中的解释进行操作,您应该在调试器中遍历代码,以便很好地理解发生了什么。但我将简要概述正在发生的事情:

正在演示的是“记忆化”,这是函数式编程中使用的一种常见优化技术。如果结果仅取决于传递给它的参数,则称该函数是纯函数。因此,如果一个函数是纯函数,您可以根据参数缓存结果——这种技术称为记忆化。如果一个函数的计算成本很高并且被多次调用,你会这样做。

用于证明这一点的经典示例(如此处)是生成斐波那契数。我不打算详细说明这些是如何计算出来的,但基本上,随着你的数字越来越高,你会越来越多地重复自己,因为每个数字都是从前面的两个数字计算出来的。通过记忆每个中间结果,您只需计算一次,从而使算法更快(当您在序列中更高时更快)。

就这段代码而言,memoizer 采用两个参数 - 'memo' 是缓存。在这种情况下,前两个值已经填写在“[0,1]”中——这些是前两个斐波那契数。

第二个参数是将应用记忆的函数。在这种情况下,递归斐波那契函数:

函数(外壳,n){返回外壳(n - 1)+外壳(n - 2);}

即结果是序列中前两个数字的总和。

memoizer 首先检查它是否已经有缓存的结果。如果确实如此,它会立即返回。如果不是,它会计算结果并将其存储在缓存中。如果不这样做,它会一次又一次地重复自己,并且一次又一次地变得非常慢,以达到序列中更高的数字。

于 2010-09-26T17:59:22.350 回答