递归调用一个javascript函数

我可以像这样在一个变量中创建一个递归函数:

/* Count down to 0 recursively.
 */
var functionHolder = function (counter) {
    output(counter);
    if (counter > 0) {
        functionHolder(counter-1);
    }
}

有了这个, functionHolder(3); 会输出3 2 1 0 。 假设我做了以下事情:

var copyFunction = functionHolder;

copyFunction(3); 将如上输出3 2 1 0 。 如果我然后改变functionHolder如下:

functionHolder = function(whatever) {
    output("Stop counting!");

然后functionHolder(3); 会给Stop counting! ,如预期。

copyFunction(3); 现在给3 Stop counting! 因为它引用了functionHolder ,而不是函数(它本身指向的)。 在某些情况下这可能是可取的,但是有没有办法编写这个函数,以便它自己调用它自己而不是保存它的变量?

也就是说,是否有可能改变行functionHolder(counter-1); 所以当我们调用copyFunction(3);时,经历所有这些步骤仍然会给出3 2 1 0 copyFunction(3); ? 我试过this(counter-1); 但是这给了我错误, this is not a function


使用命名函数表达式:

您可以给一个函数表达式一个名称,该名称实际上是私有的 ,并且只能从函数内部看到:

var factorial = function myself (n) {
    if (n <= 1) {
        return 1;
    }
    return n * myself(n-1);
}
typeof myself === 'undefined'

这里myself 只在函数本身内部可见

您可以使用此专用名称递归调用该函数。

请参阅13. Function Definition ECMAScript 5规范的13. Function Definition

FunctionExpression中的标识符可以从FunctionExpression的FunctionBody中引用,以允许函数以递归方式调用它自己。 但是,与FunctionDeclaration不同,FunctionExpression中的标识符不能被引用,也不会影响包含FunctionExpression的范围。

请注意,Internet Explorer版本8的行为不正确,因为名称实际上在封闭变量环境中可见,并且引用了实际函数的副本(请参阅下面的patrick dw的注释)。

使用arguments.callee:

或者,您可以使用arguments.callee来引用当前函数:

var factorial = function (n) {
    if (n <= 1) {
        return 1;
    }
    return n * arguments.callee(n-1);
}

ECMAScript的第5版禁止在严格模式下使用arguments.callee(),但是:

(来自MDN):在正常代码arguments.callee指的是封闭函数。 这个用例很弱:只需命名封闭函数! 此外,arguments.callee基本上阻碍了内联函数之类的优化,因为如果访问arguments.callee,必须提供对非内联函数的引用。 用于严格模式函数的arguments.callee是一个不可删除的属性,在设置或检索时抛出。


您可以使用arguments.callee [MDN]访问函数本身:

if (counter>0) {
    arguments.callee(counter-1);
}

然而,这将在严格的模式中打破。


我知道这是一个古老的问题,但我想我会提出一个可以使用的解决方案,如果你想避免使用命名函数表达式。 (不是说你应该或不应该避免它们,只是提出另一种解决方案)

  var fn = (function() {
    var innerFn = function(counter) {
      console.log(counter);

      if(counter > 0) {
        innerFn(counter-1);
      }
    };

    return innerFn;
  })();

  console.log("running fn");
  fn(3);

  var copyFn = fn;

  console.log("running copyFn");
  copyFn(3);

  fn = function() { console.log("done"); };

  console.log("fn after reassignment");
  fn(3);

  console.log("copyFn after reassignment of fn");
  copyFn(3);
链接地址: http://www.djcxy.com/p/38275.html

上一篇: Calling a javascript function recursively

下一篇: Different font faces and sizes within label text entries in ggplot2