javascript:递归匿名函数?

javascript:递归匿名函数?,javascript,recursion,scope,anonymous-function,Javascript,Recursion,Scope,Anonymous Function,假设我有一个基本的递归函数: function recur(data) { data = data+1; var nothing = function() { recur(data); } nothing(); } (function foo(data){ data++; var nothing = function() { foo(data); } nothing(); })(); (Y(fun

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

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}
(function foo(data){
    data++;
    var nothing = function() {
        foo(data);
    }
    nothing();
})();
(Y(function(recur) {
  return function(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();
})();

我想要一种方法来调用调用此函数的函数。。。我在某个地方见过一些脚本(我不记得在哪里),它们可以告诉您调用的函数的名称,但我现在记不起这些信息了。

您可以执行以下操作:

(function(data){
    var recursive = arguments.callee;
    data = data+1;
    var nothing = function() {
        recursive(data)
    }
    nothing();
})();
(foo = function() { foo(); })()
或者在您的情况下:

(recur = function(data){
    data = data+1;
    var nothing = function() {
        if (data > 100) return; // put recursion limit
        recur(data);
    }
    nothing();
})(/* put data init value here */ 0);

可以为函数命名,即使将函数创建为值而不是“函数声明”语句。换言之:

(function foo() { foo(); })();
是一个栈吹递归函数。现在,也就是说,一般来说,您需要了解,因为各种Javascript实现都存在一些奇怪的问题。(注意——这是一个相当古老的评论;Kangax博客文章中描述的一些/许多/所有问题可能在更现代的浏览器中得到修复。)

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

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

编辑-如果您希望具有可以调用自身的“匿名”函数的效果,可以执行以下操作(假设您以回调或类似方式传递函数):


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

我不会作为内联函数执行此操作。它超越了好品味的界限,并没有给你带来任何东西

如果您真的必须这样做,则在Fabrizio的回答中有
参数。被调用方
。然而,这通常被认为是不可取的,在ECMAScript第五版的“严格模式”中是不允许的。虽然ECMA3和非严格模式不会消失,但在严格模式下工作会带来更多可能的语言优化

还可以使用命名的内联函数:

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}
(function foo(data){
    data++;
    var nothing = function() {
        foo(data);
    }
    nothing();
})();
(Y(function(recur) {
  return function(data) {
    data = data+1;
    var nothing = function() {
      recur(data);
    }
    nothing();
  }
})());
然而,命名内联函数表达式也是最好避免的,因为IE的JScript对它们做了一些不好的事情。在上面的示例中,
foo
错误地污染了IE中的父作用域,并且父
foo
foo
中看到的
foo
的一个单独实例


将其放入内联匿名函数的目的是什么?如果您只是想避免污染父作用域,那么当然可以将第一个示例隐藏在另一个自调用匿名函数(命名空间)中。您真的需要每次围绕递归创建
nothing
的新副本吗?您最好使用包含两个简单的相互递归函数的名称空间。

如bobince所述,只需命名函数即可

但是,我猜您也希望传入初始值并最终停止您的函数

var initialValue = ...

(function recurse(data){
    data++;
    var nothing = function() {
        recurse(data);
    }
    if ( ... stop condition ... )
        { ... display result, etc. ... }
    else
        nothing();
}(initialValue));


当您声明这样的匿名函数时:

(function () {
    // Pass
}());
var cmTitle = 'Root' + (function cmCatRecurse(cmCat){return (cmCat == root) ? '' : cmCatRecurse(cmCat.parent) + ' : ' + cmCat.getDisplayName();})(cmCurrentCat);
它被认为是一个函数表达式,它有一个可选名称(您可以使用该名称从自身内部调用它。但由于它是一个函数表达式(而不是语句),因此它保持匿名(但有一个可以调用的名称)。因此,此函数可以调用自身:

(function foo () {
    foo();
}());
foo //-> undefined

人们在评论中谈到Y组合器,但没有人将其作为答案

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

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

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

关于此解决方案,最重要的一点是您不应该使用它。

为什么不将函数传递给函数本身

    var functionCaller = function(thisCaller, data) {
        data = data + 1;
        var nothing = function() {
            thisCaller(thisCaller, data);
        };
        nothing();
    };
    functionCaller(functionCaller, data);

使用“匿名对象”可能最简单:

你的全局空间完全没有污染。它非常简单。你可以很容易地利用对象的非全局状态

您还可以使用ES6对象方法使语法更加简洁

({
  do() {
    console.log("don't run this ...");
    this.do();
  }
}).do();

我不确定是否仍然需要答案,但也可以使用使用function.bind创建的委托完成此操作:

    var x = ((function () {
        return this.bind(this, arguments[0])();
    }).bind(function (n) {
        if (n != 1) {
            return n * this.bind(this, (n - 1))();
        }
        else {
            return 1;
        }
    }))(5);

    console.log(x);

这不涉及命名函数或参数。被调用方。

另一个答案不涉及命名函数或参数。被调用方

var sum = (function(foo,n){
  return n + foo(foo,n-1);
})(function(foo,n){
     if(n>1){
         return n + foo(foo,n-1)
     }else{
         return n;
     }
},5); //function takes two argument one is function and another is 5

console.log(sum) //output : 15

这可能不适用于所有情况,但您可以使用
参数.callee
引用当前函数

因此,阶乘可以这样做:

var fac = function(x) { 
    if (x == 1) return x;
    else return x * arguments.callee(x-1);
}
我需要(或者更确切地说,需要)一个单行匿名函数来遍历一个构建字符串的对象,并按如下方式处理它:

(function () {
    // Pass
}());
var cmTitle = 'Root' + (function cmCatRecurse(cmCat){return (cmCat == root) ? '' : cmCatRecurse(cmCat.parent) + ' : ' + cmCat.getDisplayName();})(cmCurrentCat);

它会生成一个类似于“Root:foo:bar:baz:…”的字符串。

这是对jforjs答案的修改,使用了不同的名称和稍微修改的条目

// function takes two argument: first is recursive function and second is input
var sum = (function(capturedRecurser,n){
  return capturedRecurser(capturedRecurser, n);
})(function(thisFunction,n){
     if(n>1){
         return n + thisFunction(thisFunction,n-1)
     }else{
         return n;
     }
},5); 

console.log(sum) //output : 15

无需展开第一个递归。将自身作为引用接收的函数可追溯到OOP的原始软泥。

在某些情况下,您必须依赖匿名函数。给定的是一个递归
映射
函数:

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}
(function foo(data){
    data++;
    var nothing = function() {
        foo(data);
    }
    nothing();
})();
(Y(function(recur) {
  return function(data) {
    data = data+1;
    var nothing = function() {
      recur(data);
    }
    nothing();
  }
})());
const map=f=>acc=>([head,…tail])=>head==未定义
?acc
:地图(f)([…附件,f(头部)])(尾部);
常数sqr=x=>x*x;
常数xs=[1,2,3,4,5];

log(map(sqr)([0])(xs));//[0]修改数组的结构
这是@zem答案的一个版本,带有箭头函数

您可以使用
U
Y
组合器。Y组合器是最简单的使用方法

U
combinator,使用此函数,您必须不断传递函数:

常数U=f=>f(f)
U(selfFn=>arg=>selfFn(selfFn)(“到无穷远”)

Y
combinator,使用它您不必一直传递函数:

常数Y=gen=>U(f=>gen(…args)=>f(f)(…args)))
Y(selfFn=>arg=>selfFn('到无穷大