Using Named Functions Within Self-Executing Function Blocks In Javascript

Posted August 16, 2010 at 9:25 AM by Ben Nadel

Tags: Javascript / DHTML

This is just a quick tip that I recently picked up from watching Paul Irish discuss 10 things that he learned from the jQuery source code. It was a couple of weeks ago, but I don't believe that this tip was actually something in the jQuery source code; rather, I believe it was just something that he demonstrated in one of his explantations. Anyway, what he showed me was that you could use named functions in self-executing function blocks.

Typically, when we we create a self-executing function block, we do so with an anonymous (lambda) function:

  • ( function(){ .... function body .... } )();

This works great - it takes the anonymous function and executes it immediately. As Paul demonstrated, however, the same thing can be done with a named function:

  • ( function myFunction(){ .... function body .... } )();

While this additional variable reference - myFunction - is not always needed, it does provide us with a way to create recursive, self-executing functions. In the following demo, I've created a self-executing function that increments a counter, logs it, and then calls itself recursively:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Named Self-Executing Functions</title>
  • <script type="text/javascript">
  •  
  • // Define a variable to be accessed within the
  • // self-executing function block.
  • var counter = 0;
  •  
  • // Create a self-executing function block; however, rather
  • // than passing in an anonymous, headless function, let's
  • // pass in a named function.
  • (function useCounter(){
  •  
  • // Increment and log counter.
  • console.log( ++counter );
  •  
  • // Call *this* function again in after a short timeout.
  • // Since it has a name, we don't have to use the
  • // depracated arguments.callee property.
  • setTimeout( useCounter, 1000 );
  •  
  • })(); // Self-execute.
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Intentionally left blank. -->
  • </body>
  • </html>

As you can see here, we have defined the function, useCounter(), as the target of the self-executing function block. The logic, within this self-executing function, then executes the useCounter() function recursively after a brief timeout. After letting this page run for a few seconds, I get the following console output:

1
2
3
4
5

As you can see, the self-executing behavior of the function block is exactly the same; but, we gain the added benefit of being able to reference the function in question without having to rely on deprecated features such as "arguments.callee." A small but awesome tip from Paul.




Reader Comments

Aug 16, 2010 at 9:45 AM // reply »
4 Comments

I do this slightly differently.

functionName = (function(){ ..do stuff.. })();

same thing really.


Aug 16, 2010 at 9:48 AM // reply »
8 Comments

This approach is pretty great - I'm a fan.

I picked it up from this gist from Ben Alman (which itself was forked from a gist from Remy Sharp), which shows some other ways to use this technique (such as waiting before the first execution or using setInterval instead of setTimeout).

Also, given that you're using the HTML5 doctype, you can drop the type attribute from the script tag. It felt weird at first, but I'm enjoying not having to bother with that now. :)


Aug 16, 2010 at 9:48 AM // reply »
8 Comments

Erm - I didn't actually link in the gist.

http://gist.github.com/360138

There we go. Sorry about that.


Aug 16, 2010 at 9:58 AM // reply »
1 Comments

Naming your anonymous functions is also nice because those names show up in stack traces when you debug in tools like Firebug. Seeing descriptive names there makes a world of difference when you're debugging something a few callbacks deep.


Aug 16, 2010 at 10:19 AM // reply »
66 Comments

Nice, Ben. Thanks for the smarts!


Aug 16, 2010 at 10:26 AM // reply »
11,246 Comments

@Liam,

Hmmm. I might be missing something, but I cannot get that to work for me. When I do this:

var foo = (function(){ alert( "bar" ); })();
foo();

... only the initial alert() works; the second one errors out that "foo" is undefined.

Typically, when I need to get "a" callback from the self-executing function, I need to explicitly return it:

var foo = (function(){ return( ..fn.. ); })();

... am I missing something?

@Brian,

Thanks for the link. Ben Alman definitely has a lot of great stuff! I'll be sure to check out the gist. As far as removing the "type" attribute from the Script tag, the only reason I want to shy away from that is that I actually use Script tags for other types as well (ex. type="text/template").

@Dave,

Oh cool - I hadn't even thought of that.

@Hal,

My pleasure - always happy to pass on some good stuff I get from others.

@All - a quick follow up on the concept in the context of method callbacks:

http://www.bennadel.com/blog/1989-Using-Named-Callback-Functions-In-Javascript-Methods.htm


Aug 16, 2010 at 10:44 AM // reply »
19 Comments

One caveat to this method is that it doesn't work in BlackBerry OS 5.x or earlier, as the code inside the named function expression can't access the the function by name (for whatever reason). So, if you're writing cross-OS mobile JavaScript, you should avoid this pattern.

See http://github.com/cowboy/jquery-hashchange/issues/8 for a little more information on this issue.


Aug 16, 2010 at 10:46 AM // reply »
11,246 Comments

@Cowboy,

Wow - what a strange and very specific bug!


Aug 16, 2010 at 10:57 AM // reply »
4 Comments

@Ben: forgot to mention that it needs to be inside an object. I tend to keep all my functions inside of a global object.

obj = {};
obj.funcName = (function(){ alert('hi'); })();


Aug 16, 2010 at 11:00 AM // reply »
4 Comments

actually, ignore me.. got a little muddled up..


Aug 16, 2010 at 11:10 AM // reply »
11,246 Comments

@Liam,

No worries my man :)


Aug 16, 2010 at 1:16 PM // reply »
1 Comments

hi Ben,

(
function s()
{
alert("moh");
}
)();
s();

this code do well in IE,
but doesn't work in my FireFox 3.6.8 and my opera 10

in FF it says 's' is defined in last line of the code above.

is it my fault? or something problem with the browsers.


Aug 16, 2010 at 1:58 PM // reply »
11,246 Comments

@Mohsen,

This is my experience as well. I think the self-executing block creates a kind of self-contained scope. You could probably do something like this:

var s = (function s(){ .... return(s); })();

The "return(s);" should return the local "s" reference to the calling scope, variable.


Aug 16, 2010 at 7:45 PM // reply »
22 Comments

This will work as you expect since the "calling" scope for the self-executing anonymous function is the global scope:

var foo = null;
(foo = function(){ alert( "bar" ); })();
foo();


Aug 16, 2010 at 9:30 PM // reply »
22 Comments

Just to confirm your answer about 's' is correct where the self-invoking function s has its own scope and is passed back to the global scope var s. This will also alert 's' twice as you expected:

var s = (function s(){alert('s'); return s;})(); s();

Self-invoking functions are best for once-off/initialization tasks so normally you would not return the function.


Aug 17, 2010 at 1:26 AM // reply »
6 Comments

the self executing functions of the above said styles reflect closures.


Aug 17, 2010 at 9:33 PM // reply »
11,246 Comments

@Johans,

It's an interesting thing; I just read an article posted on related blog entry about the difference between function definition and function expressions. I wonder if this comes into play here?

Anyway, thanks for pointing out that a reference to the method can be assigned within the (..) expression.


Apr 27, 2011 at 11:00 AM // reply »
1 Comments

Hiya Ben,

I just found this after a Googling 'named self-executing functions' (I had tried 'named immediately-invoked function expressions', but Cowboy's post coining that expression was the only truly relevant hit - for the record, I'm on his side ;).

I use these for the same reason you mention - ie you may want to recurse (as arguments.callee is being deprecated this reason is all the more valid) - but also, as Dave points out, because I like to name all my functions for the sake of stack tracing during debug.

Reason I Googled was because my implementation kept on getting screwed. If I might just explain the fringe case:

I don't like finishing lines with semi-colons - to my overbearing design sensibilities they make the code harder to read, and if you're bracketing and coding properly they shouldn't be necessary. Well, this can be one such case: If the previous statement isn't cut off with a semi-colon, a named immediately-invoked function expression immediately afterwards will cause a type error: previous block is not a function (or something to that extent) - even if the previous block is a function.

This doesn't happen if the function is anonymous, or if it's self-invoked by means of a preceding unary operator rather than enclosing parens. So:

  • /* Fine */
  • invocation()
  • (function(){}())
  •  
  • /* Fine */
  • invocation()
  • ~function name(){}()
  •  
  • /* TypeError */
  • invocation()
  • (function name(){}())
  •  
  • /* Fine */
  • invocation();
  • (function name(){}())

Just thought I'd share that little tidbit with y'all in case somebody lands here with the same problem I had? ;)



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools