Javascript function call recursively

I can create a recursive function in a variable as follows:

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

At the same time functionHolder(3); prints 3 2 1 0 . Say I did the following:

 var copyFunction = functionHolder; 

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

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

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

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

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

+72
javascript function recursion
Aug 15 '11 at 12:51 on
source share
5 answers

Using the named function expressions:

You can give an expression to the function name, which is actually private , and is visible only from inside the ifself function:

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

Here myself displayed only inside the function itself .

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

See 13. Function Definition the ECMAScript 5 Specification:

The identifier in a Function expression can be referenced internally by FunctionExpression FunctionBody to allow a function to call itself recursively. However, unlike FunctionDeclaration, the identifier in the Function expression cannot reference and does not affect the scope of Expression.

Please note that Internet Explorer prior to version 8 does not behave correctly, since the name does appear in the environment in which the variable is located and refers to a duplicate of the actual function (see the comment by patrick dw below).

Using arguments.callee:

Alternatively, you can use arguments.callee to reference the current function:

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

The fifth edition of ECMAScript prohibits the use of arguments.callee () in strict mode , however:

(From MDN ): In ordinary arguments, code.callee refers to a closing function. This use case is weak: just name the enable function! In addition, arguments.callee makes it very difficult to optimize, for example, built-in functions, since you must provide a reference to a non-built-in function if access.callee accesses it. arguments.callee for strict mode functions is a non-removable property that is generated during installation or recovery.

+121
Aug 15 '11 at 12:56
source share

You can access the function itself using arguments.callee [MDN] :

 if (counter>0) { arguments.callee(counter-1); } 

However, this will be violated in strict mode.

+8
Aug 15 '11 at 12:58
source share

I know this is an old question, but I thought that we would introduce another solution that you can use if you want to avoid using the named functional expressions. (Do not say that you should or should not avoid them, simply presenting another solution)

  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); 
+5
May 29 '15 at 23:36
source share

Here is one very simple example:

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

Note that counter counts back with respect to the slug value. This is due to the position in which we register these values, since the function is repeated before logging - therefore, we essentially keep the nesting deeper and deeper in the record up to . p>

As soon as recursion encounters the last element of the call stack, it will trample the โ€œexitโ€ from function calls, while the first counter increment occurs inside the last nested call.

I know that this is not a โ€œfixโ€ in the interrogation code, but given the headline, I thought that overall I would like to introduce Recursion for a better understanding of recursion, directly.

+3
Oct 18 '14 at 0:07
source share

You can use 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))); 

And you can use it like this:

 // 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); } }); 
+2
Sep 29 '15 at 18:24
source share



All Articles