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,238 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,238 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,238 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,238 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,238 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 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools