Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
111
rated 0 times [  116] [ 5]  / answers: 1 / hits: 153447  / 13 Years ago, mon, august 15, 2011, 12:00:00

I can create a recursive function in a variable like so:



/* Count down to 0 recursively.
*/
var functionHolder = function (counter) {
output(counter);
if (counter > 0) {
functionHolder(counter-1);
}
}


With this, functionHolder(3); would output 3 2 1 0. Let's say I did the following:



var copyFunction = functionHolder;


copyFunction(3); would output 3 2 1 0 as above. If I then changed functionHolder as follows:



functionHolder = function(whatever) {
output(Stop counting!);


Then functionHolder(3); would give Stop counting!, as expected.



copyFunction(3); now gives 3 Stop counting! as it refers to functionHolder, not the function (which it itself points to). This could be desirable in some circumstances, but is there a way to write the function so that it calls itself rather than the variable that holds it?



That is, is it possible to change only the line functionHolder(counter-1); so that going through all these steps still gives 3 2 1 0 when we call copyFunction(3);? I tried this(counter-1); but that gives me the error this is not a function.


More From » function

 Answers
8

Using Named Function Expressions:



You can give a function expression a name that is actually private and is only visible from inside of the function ifself:



var factorial = function myself (n) {
if (n <= 1) {
return 1;
}
return n * myself(n-1);
}
typeof myself === 'undefined'


Here myself is visible only inside of the function itself.



You can use this private name to call the function recursively.



See 13. Function Definition of the ECMAScript 5 spec:




The Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.




Please note that Internet Explorer up to version 8 doesn't behave correctly as the name is actually visible in the enclosing variable environment, and it references a duplicate of the actual function (see patrick dw's comment below).



Using arguments.callee:



Alternatively you could use arguments.callee to refer to the current function:



var factorial = function (n) {
if (n <= 1) {
return 1;
}
return n * arguments.callee(n-1);
}


The 5th edition of ECMAScript forbids use of arguments.callee() in strict mode, however:




(From MDN): In normal code arguments.callee refers to the enclosing function. This use case is weak: simply name the enclosing function! Moreover, arguments.callee substantially hinders optimizations like inlining functions, because it must be made possible to provide a reference to the un-inlined function if arguments.callee is accessed. arguments.callee for strict mode functions is a non-deletable property which throws when set or retrieved.



[#90607] Friday, August 12, 2011, 13 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
eastonb

Total Points: 498
Total Questions: 91
Total Answers: 102

Location: Tanzania
Member since Wed, Feb 24, 2021
3 Years ago
;