Sam*_*ere 87 javascript recursion function function-expression
我可以在变量中创建一个递归函数,如下所示:
/* Count down to 0 recursively.
*/
var functionHolder = function (counter) {
output(counter);
if (counter > 0) {
functionHolder(counter-1);
}
}
Run Code Online (Sandbox Code Playgroud)
有了这个,functionHolder(3);就输出了3 2 1 0.假设我做了以下事情:
var copyFunction = functionHolder;
Run Code Online (Sandbox Code Playgroud)
copyFunction(3);输出3 2 1 0如上.如果我改变functionHolder如下:
functionHolder = function(whatever) {
output("Stop counting!");
Run Code Online (Sandbox Code Playgroud)
然后functionHolder(3);会Stop counting!按预期给出.
copyFunction(3);现在给3 Stop counting!它指的是functionHolder,不是函数(它本身指向).在某些情况下这可能是理想的,但是有没有办法编写函数以便它调用自身而不是保存它的变量?
也就是说,是否可以仅更改线路,functionHolder(counter-1);以便3 2 1 0在我们呼叫时仍然通过所有这些步骤copyFunction(3);?我尝试了,this(counter-1);但这给了我错误this is not a function.
Arn*_*anc 143
您可以为函数表达式提供一个实际上是私有的名称,并且只能从函数内部看到ifself:
var factorial = function myself (n) {
if (n <= 1) {
return 1;
}
return n * myself(n-1);
}
typeof myself === 'undefined'
Run Code Online (Sandbox Code Playgroud)
这里myself是只有内部功能的可视本身.
您可以使用此专用名称以递归方式调用该函数.
参见13. Function DefinitionECMAScript 5规范:
可以从FunctionExpression的FunctionBody内部引用FunctionExpression中的标识符,以允许函数递归调用自身.但是,与FunctionDeclaration不同,FunctionExpression中的标识符不能被引用,也不会影响包含FunctionExpression的范围.
请注意,版本8以下的Internet Explorer行为不正确,因为名称实际上在封闭变量环境中可见,并且它引用了实际函数的副本(请参阅下面的patrick dw评论).
或者您可以arguments.callee用来引用当前函数:
var factorial = function (n) {
if (n <= 1) {
return 1;
}
return n * arguments.callee(n-1);
}
Run Code Online (Sandbox Code Playgroud)
第5版ECMAScript禁止在严格模式下使用arguments.callee():
(来自MDN):在普通代码中,arguments.callee引用封闭函数.这个用例很弱:只需命名封闭函数!而且,arguments.callee实际上阻碍了内联函数之类的优化,因为如果访问arguments.callee,必须能够提供对非内联函数的引用.用于严格模式函数的arguments.callee是一个不可删除的属性,在设置或检索时抛出.
Fel*_*ing 10
您可以使用arguments.callee [MDN]访问该功能:
if (counter>0) {
arguments.callee(counter-1);
}
Run Code Online (Sandbox Code Playgroud)
但是,这将在严格模式下中断.
我知道这是一个老问题,但我想如果你想避免使用命名函数表达式,我会提出一个可以使用的解决方案.(不是说你应该或不应该避免它们,只是提出另一个解决方案)
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);
Run Code Online (Sandbox Code Playgroud)
您可以使用Y-combinator:(Wikipedia)
// 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)));
Run Code Online (Sandbox Code Playgroud)
您可以这样使用它:
// 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);
}
});
Run Code Online (Sandbox Code Playgroud)