views:

380

answers:

9

Lets say I have a basic recursive function:

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}

How could I do this if I have an anonymous function such as...

(function(data){
    data = data+1;
    var nothing = function() {
        //Something here that calls the function?
    }
    nothing();
})();

I'd like a way to call the function that called this function... I've seen scripts somewhere (I can't remember where) that can tell you the name of a function called, but I can't recall any of that information right now.

+15  A: 
(function(data){
    var recursive = arguments.callee;
    data = data+1;
    var nothing = function() {
        recursive(data)
    }
    nothing();
})();
Fabrizio Calderan
I hope everybody voting for this (technically correct) answer realizes the problems with `arguments.callee`: it's disallowed in strict mode and in ES5.
Pointy
A: 

arguments.callee.caller??

from this post:

http://stackoverflow.com/questions/280389/javascript-how-do-you-find-the-caller-function

maxthephilosopher
Using `arguments.call*` is considered bad practice and is removed in ES5 Strict.
indieinvader
Please use comments to indicate duplicates, not answers. (Wasn't my downvote, but it's justified, IMHO.)
Roger Pate
+5  A: 

You could do something like:

(foo = function() { foo(); })()

or in your case:

(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);
ArtBIT
You could do with declaring `recur` first with a `var` statement. Dunno whether that breaks the rules of the question, but as you have it now, without the `var` statement you'll get an error in ECMAScript 5 strict mode.
Tim Down
My initial comment included the `var` keyword, but once I tested this code, it was throwing errors, since you cannot really declare a variable inside of a self-invoking block, and my approach relies on auto declaration of an undefined variable, and therefore @Pointy's solution is more correct.But I still voted for Fabrizio Calderan answer though ;)
ArtBIT
Yes, doing `(var recur = function() {...})();` won't work since it's now a statement rather than an assignment expression (which returns the value assigned). I was suggesting `var recur; (recur = function() {...})();` instead.
Tim Down
+10  A: 
Pointy
Can we avoid polluting the global namespace another way with ES5 sctrict (I haven't read deep into ES5 yet)?
See my edits ...
Pointy
A: 

http://stackoverflow.com/questions/280389/javascript-how-do-you-find-the-caller-function

zod
Please use comments to indicate duplicates, not answers. (Wasn't my downvote, but it's justified, IMHO.)
Roger Pate
I was unknown about that, my mistake. one down vote is ok. But more than one is not fair.i will be more careful before posting :(
zod
+5  A: 

I would not do this as an inline function. It's pushing against the boundaries of good taste and doesn't really get you anything.

If you really must, there is arguments.callee as in Fabrizio's answer. However this is generally considered inadvisable and is disallowed in ECMAScript Fifth Edition's ‘strict mode’. Although ECMA 3 and non-strict-mode are not going away, working in strict mode promises more possible language optimisations.

One can also use a named inline function:

(function foo(data){
    data++;
    var nothing = function() {
        foo(data);
    }
    nothing();
})();

However named inline function expressions are also best avoided, as IE's JScript does some bad things to them. In the above example foo incorrectly pollutes the parent scope in IE, and the parent foo is a separate instance to the foo seen inside foo.

What's the purpose of putting this in an inline anonymous function? If you just want to avoid polluting the parent scope, you can of course hide your first example inside another self-calling-anonymous-function (namespace). Do you really need to create a new copy of nothing each time around the recursion? You might be better off with a namespace containing two simple mutually-recursive functions.

bobince
I agree, a named function is more suitable than arguments.callee not only for the ecmascript strict mode, but also for a matter of optimization because at each recursion he need to get a reference to the callee (and this probably could reduce the execution speed)
Fabrizio Calderan
+1 for the poetic, `"pushing against the boundaries of good taste"` - (well, and the good info).
Peter Ajtai
what about a simple pre/postfix if pollution is really a concern here? Considering that it's not in the global scope (even if the function is top lvl, he should already have an anonymous function wrapping his whole code) it's really unlikely that a name like `recur_foo` will collide with a function in the parent scope (or to be ill-used) .
galambalazs
Very interesting - http://jsfiddle.net/hck2A/ - IE does pollute the parent in this case, like you said. Never realized that.
Peter Ajtai
@Peter: http://kangax.github.com/nfe/ (especially ‘JScript bugs’) for more than you ever wanted to know on this subject. It's finally fixed in IE9 (but only in IE9 Standards Mode).
bobince
+1  A: 

Like bobince wrote, simply name your function.

But, I'm guessing you also want to pass in an initial value and stop your function eventually!

var initialValue = ...

(function recurse(data){
    data++;
    var nothing = function() {
        recurse(data);
    }
    if ( ... stop condition ... )
        { ... display result, etc. ... }
    else
        nothing();
}(initialValue));

working jsFiddle example (uses data += data for fun)


Peter Ajtai
+1, This is a very useful answer and you should get more upvotes for it, but it's not anonymous.
you clearly didn't read what bobince wrote: `However named inline function expressions are also best avoided.`. But the OP misses the point too... :)
galambalazs
@Galamb - I read it. Disallowed in strict mode and in ES5 is not the same as polluting a parent scope and creating extra instances.
Peter Ajtai
A: 

When you declare an anonymous function like this:

(function () {
    // Pass
}());

Its considered a function expression and it has an optional name (that you can use to call it from within itself. But because it's a function expression (and not a statement) it stays anonymous (but has a name that you can call). So this function can call itself:

(function foo () {
    foo();
}());
foo //-> undefined
indieinvader
+1  A: 

People talked about the Y combinator in comments, but no one wrote it as an answer.

The Y combinator can be defined in javascript as follows: (thanks to steamer25 for the link)

var Y = function (gen) {
  return (function(f) {
    return f(f);
  }(function(f) {
    return gen(function() {
      return f(f).apply(null, arguments);
    });
  }));
}

And when you want to pass your anonymous function:

(Y(function(recur) {
  return function(data) {
    data = data+1;
    var nothing = function() {
      recur(data);
    }
    nothing();
  }
})());

The most important thing to note about this solution is that you shouldn't use it.

zem