javascript:递归匿名函数?

假设我有一个基本的递归函数:

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}

如果我有一个匿名函数,我怎么能这样做,比如...

(function(data){
    data = data+1;
    var nothing = function() {
        //Something here that calls the function?
    }
    nothing();
})();

我想要一种方法来调用调用此函数的函数...我在某个地方看到过脚本(我不记得在哪里),可以告诉你一个被调用的函数的名称,但我现在想不起任何这些信息。


答案 1

您可以为函数命名,即使将函数创建为值而不是“函数声明”语句也是如此。换句话说:

(function foo() { foo(); })();

是一个堆栈吹制递归函数。现在,也就是说,你可能不想这样做,因为Javascript的各种实现存在一些奇怪的问题。(注意 - 这是一个相当古老的评论;Kangax博客文章中描述的一些/许多/所有问题都可以在更现代的浏览器中修复。

当你给出这样一个名字时,这个名字在函数之外是不可见的(好吧,它不应该是;这是其中一个奇怪的地方)。这就像Lisp中的“letrec”。

至于 ,这在“严格”模式下是不允许的,通常被认为是一件坏事,因为它使一些优化变得困难。它也比人们预期的要慢得多。arguments.callee

edit — 如果你想获得一个可以调用自身的“匿名”函数的效果,你可以做这样的事情(假设你把函数作为回调或类似的东西传递):

asyncThingWithCallback(params, (function() {
  function recursive() {
    if (timeToStop())
      return whatever();
    recursive(moreWork);
  }
  return recursive;
})());

这样做是使用一个漂亮,安全,未损坏的IE函数声明语句定义一个函数,创建一个本地函数,其名称不会污染全局命名空间。包装器(真正的匿名)函数只返回该本地函数。


答案 2

人们在评论中谈论Y组合器,但没有人把它作为答案。

Y组合器可以在javascript中定义如下:(感谢steamer25的链接)

var Y = function (gen) {
  return (function(f) {
    return f(f);
  }(function(f) {
    return gen(function() {
      return f(f).apply(null, arguments);
    });
  }));
}

当您想要传递匿名函数时:

(Y(function(recur) {
  return function(data) {
    data = data+1;
    var nothing = function() {
      recur(data);
    }
    nothing();
  }
})());

关于此解决方案,需要注意的最重要的事情是,您不应该使用它。