2011-12-17 98 views
9

读一本书的例子,有人可以解释函数调用斐波那契如何在函数本身没有声明任何参数时接受参数'i'吗?Javascript记忆说明?

var fibonacci = (function() { 
    var memo = [0, 1]; 
    var fib = function (n) { 
     var result = memo[n]; 
     if (typeof result !== 'number') { 
      result = fib(n - 1) + fib(n - 2); 
      memo[n] = result; 
     } 
     return result; 
    }; 
    return fib; 
}()); 

for(var i = 0; i <= 10; i += 1) { 
    document.writeln('// ' + i + ': ' + fibonacci(i)); 
} 

回答

15

您正在创建一个自执行匿名函数(function(){}());,其中返回fib函数,该函数接受一个参数。 var fib = function(n){} ... return fib;

var fibonacci = (function() { // Self-executing anonymous function 
    var memo = [0, 1];   // local variable within anonymous function 
    var fib = function (n) { // actual fib function (takes one argument) 
     var result = memo[n]; 
     if (typeof result !== 'number') { 
      result = fib(n - 1) + fib(n - 2); 
      memo[n] = result; 
     } 
     return result; 
    }; 
    return fib; // return fib (fibonacci is now set to the function fib defined above, which takes one argument) 
}()); 

该系统(返回从自执行匿名函数的函数)允许您以仍然可以通过返回的函数可以使用局部范围定义变量,而不是由职能超出范围。这是一个example

这种技术在JavaScript中被称为closure。了解更多关于它的MDN guide.

+4

值得注意的是,即使在outter函数返回后,内函数访问变量函数的技巧也被称为'closure' – 7hi4g0 2013-11-07 17:43:24

+0

这是书中的Javascript - 好的部分,还有更好的部分那里的过程描述。 – 2015-12-08 11:29:58

2
var fibonacci = (function() { 
    ... 
    return fib; 
})(); 

这是自动执行的功能。

它声明的函数表达式,它返回一个函数(fib),立即执行外部函数表达式(()),并分配它的返回值(这是fib)到fibonacci变量。

1

函数fibonacci确实带有一个参数。请注意,从第一行开始的未命名函数不是最终被称为fibonacci的函数。这个未命名的函数会立即被调用,因为在关闭大括号}后立即有()。这个未命名的函数返回fib,一个局部变量,其中分配了单参数函数。因此,fibonacci结束参照即fibonacci由无名函数返回的功能,是这样的:

var fib = function (n) { 
    var result = memo[n]; 
    if (typeof result !== 'number') { 
     result = fib(n - 1) + fib(n - 2); 
     memo[n] = result; 
    } 
    return result; 
}; 

注意,该功能是指用于memoizing的目的无名函数的局部变量。

关键的一点需要注意是()它调用匿名函数立刻,这里有一些例子,说明了这种方法:

var a = (function() { return 1; }); 

可变a持有其返回1

var a = (function() { return 1; }()); 

功能然而在此,变量a保持值1.

6

因为函数返回的功能带参数。

3

存在与标识符fib然后将其分配给标识符fibonacci返回功能的自调用函数。这样你就可以创建一个私人变量memo,这个变量只能被该函数访问。所以var fibonacci实际上是function(n){...}

5

为了理解这一点,我认为使用更简单的示例很有帮助。看看下面两个memoized函数。唯一的区别是成功记忆代码后()add : function(){ ... }()

var failed_memoization = { 
     add : function(){ 
      var counter; 
      return function(number){ 
       if(counter){ 
        counter = counter + number; 
        return counter; 
       } 
       counter = number; 
       return counter; 
      } //NOTE: NO function call brackets here 
     } 
    } 

    var successful_memoization = { 
     add : function(){ 
      var counter; 
      return function(number){ 
       if(counter){ 
        counter = counter + number; 
        return counter; 
       } 
       counter = number; 
       return counter; 
      } 
     }() //NOTE: the function call brackets here!! 
    }; 
} 

现在让我们执行这两个函数。

console.log('Failed Memoization'); 
console.log(failed_memoization.add(5));  //We wanted 5, but this prints the text of the function instead.... Okay, lets try something else 
console.log(failed_memoization.add()(5)); //5 
console.log(failed_memoization.add()(10)); //10 (Wanted it to be 5+10 = 15. 
console.log('successful_memoization'); 
console.log(successful_memoization.add(8)); //8 
console.log(successful_memoization.add(16)); //24 (This is what we wanted 8 + 16 = 24) 

那么,什么是怎么回事是,successful_memoization当我们把()add : function(){...}()结束。同样,这个函数在创建静态对象时立即执行。反过来,执行该函数返回对象function (number){...},其结果在于:add : function (number){...}不是add : function(){}它最初出现。

什么还重要的是要注意的是,var counter声明return function(name){}。由于它仍在add : function(number){...}内使用,因此可以在该函数中访问此变量。对于failed_memoization.add()(number),我们每次执行该函数时都会使用新的counter,因为我们执行第一个函数,然后执行每个调用的内部函数。对于successful_memoization.add(number),我们在初始化时执行了外部函数,因此counter将在所有后续调用中保留,并且不会被覆盖。