javascript:recursion匿名函数?

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

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

我怎么能做到这一点,如果我有一个匿名的function,如…

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

我想要一个方法来调用函数调用这个函数…我见过脚本某处(我不记得在哪里),可以告诉你一个函数的名称叫,但我不记得任何那个信息现在。

可以给这个函数一个名字,即使你把这个函数创build为一个值而不是“函数声明”语句。 换一种说法:

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

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

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

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

编辑 – 如果你想有一个可以调用自己的“匿名”函数的效果,你可以做这样的事情(假设你将函数作为callback或类似的东西传递):

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

所做的就是定义一个带有一个好的,安全的,没有破坏的IE函数声明语句的函数,创build一个名称不会污染全局名称空间的本地函数。 包装器(真正的匿名)函数只是返回本地函数。

人们在评论中提到了Y组合者,但没有人把它写成答案。

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

 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(); } })()); 

关于这个解决scheme最重要的一点是你不应该使用它。

 (function(data){ var recursive = arguments.callee; data = data+1; var nothing = function() { recursive(data) } nothing(); })(); 

我不会做这个内联函数。 它推动着高品味的界限,并没有真正吸引你。

如果你真的必须的话,就像Fabrizio的答案一样,有arguments.callee 。 但是,这通常被认为是不可取的,并且在ECMAScript第五版的“严格模式”中是不允许的。 尽pipeECMA 3和非严格模式不会消失,但是在严格模式下工作可能会有更多可能的语言优化。

也可以使用一个命名的内联函数:

 (function foo(data){ data++; var nothing = function() { foo(data); } nothing(); })(); 

但是,最好避免使用内联函数expression式,因为IE的JScript对它们做了一些不好的事情。 在上面的例子中, foo错误地污染了IE中的父范围,并且父foofoo看到的foo的单独实例。

将这个内联匿名函数的目的是什么? 如果您只是想避免污染父范围,那么您当然可以将您的第一个示例隐藏在另一个自调用匿名函数(命名空间)中。 你是否真的需要在recursion周围创build一个nothing的新副本? 包含两个简单的相互recursion函数的命名空间可能会更好。

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

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

您的全球空间完全没有受到污染。 这非常简单。 而且你可以很容易地利用对象的非全局状态。

你可以做这样的事情:

 (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); 

U combinator

U组合器接受一个函数并将其应用于自身。 所以你给它的函数应该至less有一个参数绑定到函数(本身)

在下面的例子中,我们没有退出条件,所以我们只会无限循环,直到发生堆栈溢出

 const U = f => f(f) U (f => (console.log('stack overflow imminent!'), f(f))) 

当你声明一个这样的匿名函数时:

 (function () { // Pass }()); 

它被认为是一个函数expression式,它有一个可选的名称(可以用来从它自己内部调用它,但是因为它是一个函数expression式(而不是一个语句),它保持匿名(但是有一个名字,你可以调用)。这个函数可以调用它自己:

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

为什么不把函数本身传递给函数呢?

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

在某些情况下,您必须依靠匿名function。 给定是一个recursionmap函数:

 const map = f => acc => ([head, ...tail]) => head === undefined ? acc : map (f) ([...acc, f(head)]) (tail); const sqr = x => x * x; const xs = [1,2,3,4,5]; console.log(map(sqr) ([0]) (xs)); // [0] modifies the structure of the array 

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

  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); 

这不涉及命名的函数或arguments.callee。

像bobince写的,只需简单说一下你的function。

但是,我猜你还想传递一个初始值,并最终停止你的function!

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

工作jsFiddle的例子(使用数据+ =数据的乐趣)

另一个不涉及命名函数或arguments.callee的答案

 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 

我需要(或者更确切地说)想要一个单线程的匿名函数来向上build立一个string,并像这样处理它:

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

这会产生一个像“Root:foo:bar:baz:…”这样的string。

使用ES2015,我们可以使用语法和滥用默认参数和thunks来玩一下。 后者只是没有任何争论的function:

 const applyT = thunk => thunk(); const fib = n => applyT( (f = (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)) => f(0, 1, n) ); console.log(fib(10)); // 55 // Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55... 

这是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 

没有必要展开第一次recursion。 接受自身作为参考的function回到OOP的原始渗透。

这是带有箭头function的@ zem答案的一个版本。

您可以使用UY组合器。 Y combinator是最简单的使用。

U combinator,与此你必须不断传递函数: const U = f => f(f) U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))

Y const Y = gen => U(f => gen((...args) => f(f)(...args))) Y(selfFn => arg => selfFn('to infinity and beyond'))

这可能无处不在,但你可以使用arguments.callee引用当前的函数。

所以,因子可以这样做:

 var fac = function(x) { if (x == 1) return x; else return x * arguments.callee(x-1); }