递归调用javascript函数
我可以在变量中创建递归函数,如下所示:递归调用javascript函数,javascript,function,recursion,function-expression,Javascript,Function,Recursion,Function Expression,我可以在变量中创建递归函数,如下所示: /* Count down to 0 recursively. */ var functionHolder = function (counter) { output(counter); if (counter > 0) { functionHolder(counter-1); } } 有了这个,函数保持器(3)将输出3210。假设我做了以下工作: var copyFunction = functionHo
/* Count down to 0 recursively.
*/
var functionHolder = function (counter) {
output(counter);
if (counter > 0) {
functionHolder(counter-1);
}
}
有了这个,函数保持器(3)代码>将输出3
2
1
0
。假设我做了以下工作:
var copyFunction = functionHolder;
copyFunction(3)代码>将如上所述输出3
2
1
0
。如果我随后更改了函数持有者
,如下所示:
functionHolder = function(whatever) {
output("Stop counting!");
然后函数保持器(3)代码>将给出<代码>停止计数代码>,如预期
copyFunction(3)代码>现在给出3
停止计数代码>指的是函数持有者
,而不是它本身所指的函数。在某些情况下,这可能是可取的,但是有没有一种方法来编写函数,以便它调用自己而不是保存它的变量
也就是说,是否可以仅更改行函数保持器(计数器-1)代码>这样,当我们调用复制函数(3)时,通过所有这些步骤仍然会得到3
2
1
0
代码>?我试过这个(计数器-1)
但这给了我一个错误这不是一个使用命名函数表达式的函数
:
您可以为函数表达式指定一个名称,该名称实际上是private,并且只能从函数ifself内部看到:
var factorial = function myself (n) {
if (n <= 1) {
return 1;
}
return n * myself(n-1);
}
typeof myself === 'undefined'
ECMAScript的第5版禁止在中使用参数。callee(),但是:
(From):在普通代码参数中。被调用方指的是封闭函数。这个用例很弱:只需命名封闭函数!此外,arguments.callee实质上阻碍了诸如内联函数之类的优化,因为如果访问arguments.callee,则必须能够提供对未内联函数的引用。arguments.callee是严格模式函数的不可删除属性,在设置或检索时抛出
您可以使用以下方式访问函数本身:
但是,这将在严格模式下中断。下面是一个非常简单的示例:
请注意,计数器
相对于slug
的值“向后”计数。这是因为我们记录这些值的位置,因为函数在记录之前递归——因此,在记录发生之前,我们基本上一直在调用堆栈中嵌套得越来越深
一旦递归满足最后一个调用堆栈项,它就会“跳出”函数调用,而计数器的第一个增量发生在最后一个嵌套调用的内部
我知道这不是发问者代码的“修复”,但考虑到标题,我想我会举一个递归的例子,以便更好地理解递归。我知道这是一个老问题,但我想如果你想避免使用命名函数表达式,我会再提出一个解决方案。(不是说你应该或不应该回避它们,只是提出另一种解决方案)
您可以使用Y-combinator:()
您可以这样使用它:
// 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);
}
});
我相信这是不赞成的(在严格模式下是不允许的)@Felix:是的,“严格模式”会给出一个类型错误
,但我还没有发现任何正式声明参数的内容。被调用方
(或任何违反严格模式的行为)在“严格模式”之外是不赞成的。谢谢你的回答!这两种方法都很有帮助,并以两种不同的方式解决了问题。最后,我随机决定接受哪一个:P+1,尽管它在IE8中有一点缺陷,而且imf
在封闭的变量环境中实际上是可见的,并且它引用了实际imf
函数的副本。不过,您应该能够将外部引用设置为null
。谢谢您的回答!这两种方法都很有帮助,并以两种不同的方式解决了问题。最后,我随机决定接受哪一个:只是为了让我理解。在每次返回时乘以函数的原因是什么<代码>返回n*1(n-1)代码>?为什么函数是这样工作的?if循环4次后。根据一些引用参数。被调用方将无法在严格模式下工作。NB在函数内部,这是指函数执行的上下文,而不是函数本身。在您的例子中,这可能指向全局窗口对象。
if (counter>0) {
arguments.callee(counter-1);
}
var counter = 0;
function getSlug(tokens) {
var slug = '';
if (!!tokens.length) {
slug = tokens.shift();
slug = slug.toLowerCase();
slug += getSlug(tokens);
counter += 1;
console.log('THE SLUG ELEMENT IS: %s, counter is: %s', slug, counter);
}
return slug;
}
var mySlug = getSlug(['This', 'Is', 'My', 'Slug']);
console.log('THE SLUG IS: %s', mySlug);
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);
// 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)));
// 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);
}
});