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('到无穷大