我希望可以在这里发布此问题,即使我也已将其发布在其他网站上。如果我没有遵循正确的协议(protocol),我深表歉意,请立即通知我,以便我删除帖子并学习我的类(class)。

我已经担任前端开发人员超过一年了。我去学校学习Web开发,就简单的JavaScript知识而言,我认为自己是一个有能力的编码器。
但是当涉及到编写任何类型的斐波那契函数时,我做不到。好像我的大脑中缺少一块可以理解如何处理这个简单的数字序列的部分。
这是一段有效的代码,我敢肯定我是从John Resig的书或在线的某处获得的:

fibonacci = (function () {
    var cache = {};
    return function (n) {

        var cached = cache[n];
        if (cached) return cached;

        if (n <= 1) return n;
        console.log(n);

        return (cache[n] = fibonacci(n - 2) + fibonacci(n - 1));
    };
}());

当我以10作为参数调用此函数时,得到以下序列:10,8,6,4,2,3,5,7,9

这是我的理解:

给fibonnaci分配了立即调用的函数表达式(或自执行等等),无论传递了什么参数,缓存都会启动到该表达式。
如果论点已经存在,我们就将其归还,并在永远的和平中过着我们的生活。
如果自变量等于或小于1,那也就是函数的结尾,那么永久的和平将再次出现。
但是,如果这两个条件都不存在,则该函数返回此语句,使我感到自己就像是只穿西装的猴子。

我想做的是按照正确的顺序生成前10个斐波那契数字,因为如果我能够做到这一点,那么我会觉得我至少了解它。

因此,当前两个条件失败时,代码将创建一个新的缓存变量,并将其设置为与fibonacci函数的结果相等,并且传递的参数为负2,然后将结果加负1 ....现在针对我的问题
  • 问题1:如果从未计算过fibonacci(n),函数如何知道什么是fibonacci(n-2)?
  • 问题2:递归函数是线性的,还是遵循什么顺序?
  • 问题3:如果我听不懂,我是否有成为一名程序员的希望?

  • 感谢您的时间。

    经过这个块之后,我对函数进行了一些更改,以查看是否可以保留变量中的结果并将其输出,以查看发生了什么,并且得到了一些非常意外的结果。

    这是更改:
    fibonacci = (function () {
            var cache = {};
            return function (n) {
    
                var cached = cache[n];
                if (cached) {
                    console.log(cached);
                    return cached;
                }
    
                if (n <= 1) {
                    console.log(n);
                    return n;
                }
                console.log(n);
    
                var result = (cache[n] = fibonacci(n - 2) + fibonacci(n - 1));
                console.log(result);
                return result;
            };
        }());
    

    这是结果模式:
    10,8,6,4,2,0,1,1,3,1,1,2,3,5,2,3,5,8,7,5,8,13,21,9,13, 21,34,55
    为什么会发生这种情况有帮助吗?

    最佳答案

    好吧,让我们从您了解的内容(或说您了解的内容)开始:



    不太完全:为fibonnaci分配了IIFE的返回值。有区别。在IIFE中,我们设置了return function(n)语句。顾名思义,IIFE被立即调用。该函数将被创建,执行,并且一旦返回,就不会(明确地)在任何地方被引用。返回该函数,并将其分配给变量fibonacci
    此IIFE确实创建了一个对象文字,称为cache。该对象位于IIFE的范围内,但是because of JS's scope scanning(此答案链接到其他对象……所有这些都一起解释了JS如何将名称解析为它们的值),该对象仍可供返回的函数访问,该函数现已分配给了fibonaci。



    好了,现在不再在每个函数调用中一遍又一遍地创建cache(IIFE仅被调用一次,而这就是cache的创建地)。如果返回的函数(fibonnaci)对其进行了更改,则对该对象的更改将保留在内存中。闭包变量,为此cache可用于保持函数调用之间的状态。您说的所有其他内容(n <= 1)是标准的递归函数类……这是防止无限递归的条件。



    好吧,这实际上是有趣的部分。这就是真正的魔术发生的地方。
    正如我所解释的,fibonnaci没有引用IIFE,而是引用了返回的函数:

    function(n)
    {
        var cached = cache[n];
        if (cached)
        {
            return cached;
        }
        if (n <= 1)
        {
            return n;
        }
        return (cache[n] = (fibonacci(n-2) + fibonnaci(n-1)));
    }
    

    这意味着,每次出现的fibonacci都可以用函数体代替。调用fibonnaci(10)时,最后一个(返回)语句应读取为:

    return(cahce [n] = fibonacci(8)+ fibonnaci(9));

    如您所见,现在,在返回值中调用了fibonacci(8)fibonnaci(9)。这些表达式也可以完整写成:
    return (cache[10] = (fibonnaci(6) + fibonacci(7)) + (fibonacci(7) + fibonacci(8)));
    //which is, actually:
    return (cache[10 = ( retrun (cache[6] = fibonacci(4) + fibonacci(5))
                       //since fibonacci(6) cached both fibonacci(5) & fibonacci(6)
                         + return (cache[7] = cache[5] + cache[6])
               + return cache[7] + return (cache[8] = cache[6] + cache[7]
    

    这就是缓存功能实际上是如何结合在一起的...

    我们可以重复此过程,直到调用fibonnacci(1)fibonacci(0)为止,因为在这种情况下为n<=1,并且将在不进行任何递归调用的情况下将其返回。
    还要注意,在完整编写fibonnaci(9)时,实际上将其分解为fibonacci(7) + fibonacci(8),这两个调用都是在之前进行的,因此才缓存了结果。如果您不缓存每个调用的结果,那么您将浪费时间两次计算同一件事...

    顺便说一句:该代码非常“适合”,并且可以工作,因为规范指出赋值表达式(cache[n] = ...)的计算结果为赋值,实际上,您将返回cache[n]

    关于JavaScript斐波那契分解,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18980531/

    10-11 11:20