首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >递归调用javascript函数

递归调用javascript函数
EN

Stack Overflow用户
提问于 2011-08-15 12:51:31
回答 5查看 152.8K关注 0票数 93

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

代码语言:javascript
复制
/* Count down to 0 recursively.
 */
var functionHolder = function (counter) {
    output(counter);
    if (counter > 0) {
        functionHolder(counter-1);
    }
}

这样,functionHolder(3);将输出3 2 1 0。假设我做了以下几件事:

代码语言:javascript
复制
var copyFunction = functionHolder;

copyFunction(3);将输出如上所述的3 2 1 0。如果我随后将functionHolder更改如下:

代码语言:javascript
复制
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?我尝试了this(counter-1);,但这给了我错误this is not a function

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-08-15 12:56:58

使用命名函数表达式:

您可以给一个函数表达式一个名称,这个名称实际上是专用的,并且只能从函数的内部看到,如果是:

代码语言:javascript
复制
var factorial = function myself (n) {
    if (n <= 1) {
        return 1;
    }
    return n * myself(n-1);
}
typeof myself === 'undefined'

在这里,myself只在函数本身中可见

您可以使用这个私有名称递归地调用函数。

参见13. Function Definition的ECMAScript 5规范:

FunctionExpression中的标识符可以从FunctionExpression的FunctionBody中引用,从而允许函数递归地调用自己。但是,与FunctionDeclaration不同的是,FunctionExpression中的标识符不能被引用,也不影响包含FunctionExpression的作用域。

请注意,到第8版为止的Internet没有正确的行为,因为名称实际上在封闭的可变环境中是可见的,它引用了实际函数的副本(请参见下面patrick dw的注释)。

使用arguments.callee:

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

代码语言:javascript
复制
var factorial = function (n) {
    if (n <= 1) {
        return 1;
    }
    return n * arguments.callee(n-1);
}

然而,第5版的ECMAScript禁止在严格模式中使用arguments.callee():

(来自MDN):在正常代码中,arguments.callee指的是封闭函数。这个用例是弱的:简单地命名封装函数!此外,arguments.callee在很大程度上阻碍了像内联函数这样的优化,因为如果访问arguments.callee,必须使它能够提供对无内联函数的引用。用于严格模式函数的arguments.callee是一个不可删除的属性,它在设置或检索时抛出。

票数 150
EN

Stack Overflow用户

发布于 2015-09-29 18:24:11

您可以使用Y-组合器:(维基百科)

代码语言:javascript
复制
// ES5 syntax
var Y = function Y(a) {
  return (function (a) {
    return a(a);
  })(function (b) {
    return a(function (a) {
      return b(b)(a);
    });
  });
};

// ES6 syntax
const Y = a=>(a=>a(a))(b=>a(a=>b(b)(a)));

// If the function accepts more than one parameter:
const Y = a=>(a=>a(a))(b=>a((...a)=>b(b)(...a)));

你可以用它作为:

代码语言:javascript
复制
// ES5
var fn = Y(function(fn) {
  return function(counter) {
    console.log(counter);
    if (counter > 0) {
      fn(counter - 1);
    }
  }
});

// ES6
const fn = Y(fn => counter => {
  console.log(counter);
  if (counter > 0) {
    fn(counter - 1);
  }
});
票数 6
EN

Stack Overflow用户

发布于 2015-05-29 23:36:43

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

代码语言:javascript
复制
  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);
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7065120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档