15

When I have some code I need to execute more than once I wrap it up in a function so I don't have to repeat myself. Sometimes in addition there's a need to execute this code initially on page load. Right now I do it this way:

function foo() {
   alert('hello');
}

foo();

I would rather do it this way:

(function foo() {
   alert('hello');
})();

Problem is, this will only execute on page load but if I try to call it subsequent times using foo() it won't work.

I'm guessing this is a scope issue but is there any way to get self executing functions to work upon getting called later?

RobG
  • 142,382
  • 31
  • 172
  • 209
  • 1
    I'm not sure if this is the best way to do it. I imagine this will get real messy after a while. –  Jun 05 '12 at 00:53
  • 3
    Possible duplicate of http://stackoverflow.com/questions/6211466/call-immediately-executing-function-from-outside. – apsillers Jun 05 '12 at 00:57
  • Also possible duplicate of http://stackoverflow.com/questions/6404196/can-i-name-a-javascript-function-and-execute-it-immediately (which has better answers, IMHO, but the phrasing of the question is less of an exact match.) – apsillers Jun 05 '12 at 01:01
  • @apsillers the question is a duplicate but the 1 answer just says to do what I was already doing. –  Jun 05 '12 at 01:03
  • @Jake True enough; that's why I posted the second link. – apsillers Jun 05 '12 at 01:04
  • It will work in IE because it treats named function expressions as function declarations. That's why named function expressions are [recommended against](http://kangax.github.com/nfe/#jscript-bugs). – RobG Jun 05 '12 at 03:12

4 Answers4

34

If your function doesn't rely on a return value, you can do this...

var foo = (function bar() {
   alert('hello');
   return bar;
})();   // hello

foo();  // hello

This uses the local reference bar in the named function expression to return the function to the outer foo variable.


Or even if it does, you could make the return value conditional...

var foo = (function bar() {
   alert('hello');
   return foo ? "some other value" : bar;
})();   // hello

alert( foo() );  // hello --- some other value

or just manually assign to the variable instead of returning...

var foo; 
(function bar() {
   alert('hello');
   foo = bar;
})();   // hello

foo();  // hello

As noted by @RobG, some versions of IE will leak the identifier into the enclosing variable scope. That identifier will reference a duplicate of the function you created. To make your NFE IE-safe(r), you can nullify that reference.

bar = null;

Just be aware that the identifier will still shadow an identifier with the same name up the scope chain. Nullifying won't help that, and local variables can not be deleted, so choose the NFE name wisely.

Community
  • 1
  • 1
  • Named function expressions **should** be very useful, but they are [broken in IE](http://kangax.github.com/nfe/#jscript-bugs) so recommended against by most. e.g. in the above `typeof bar` shows "function" even if placed *before* the IIFE. – RobG Jun 05 '12 at 02:13
  • @RobG: True, but it is often an innocuous issue. The fact that `bar` leaks out and even creates a duplicate function would probably only matter if you're using that identifier in the enclosing scope to reference a variable further up the scope chain. –  Jun 05 '12 at 03:11
  • It's not an issue here, but generally the intention of function expressions is to keep the function "private". Allowing it to become a global function may have unintended consequences, especially in larger projects. – RobG Jun 05 '12 at 12:47
  • @RobG: That's a good point. I'll add a note about nullifying the leaked identifier for IE8 and lower. *(If I remember correctly, IE9 squashed this.)* –  Jun 05 '12 at 13:10
  • —unfortunately, more than half of IE web vistors (about 10% of all visitors) are using 8 or lower. – RobG Jun 06 '12 at 02:15
  • I know this is an old question but where should you add `bar = null` and is it needed for all three snippets of code? – TarranJones Jul 01 '15 at 08:19
  • @TarranJones: Put it in the same variable scope where you're creating the `bar` function. So basically on the line below the creation of the `bar` function would be fine. *(Meaning after the `})();` line.)* –  Jul 01 '15 at 15:24
  • Ok so this is great for neat code, but isn't this using up more bytes in both the browser memory and the file size for the js needing to be downloaded to execute? – Stefan P Aug 07 '15 at 23:47
  • Just figured out because the named function expression has it's own private scope you can use any function name within it, so could just use a single letter... `(function a(...` and `return a;` so the difference in size would be minimal from a file size perspective. Am I correct in thinking this? – Stefan P Aug 08 '15 at 00:00
  • @Stefan: Yes, that would save a few bytes, though if you're using an obfuscator like UglifyJS (which hopefully you are if you're concerned about file size), then it'll handle it for you. And you're right about the scope. The name isn't exposed outside that function. –  Aug 16 '15 at 01:54
  • Is this safe to use? I am returning my function with the name '_' so its simple but I don't want issues in IE... Any updates? – Taylor A. Leach Jul 19 '18 at 18:12
5

If foo() is intended to be a global function, i.e., a property of window, you can do this:

(window.foo = function() {
   alert('hello');
})();

// at some later time
foo();

The expression in the first set of parentheses does the assignment to create foo, but also evaluates to be the function so you can invoke it immediately with () on the end.

This pattern works even if the function is supposed to return a value.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • +1 No reason this couldn't be done with locals as well. `var foo; (foo = func...})()` –  Jun 05 '12 at 13:19
  • Thanks @amnotiam. Of course you're right about locals. For some reason when I wrote this answer I was tring to keep it as a single statement and avoid a var statement - I don't even remember why now. – nnnnnn Jun 05 '12 at 14:00
4

To be called from outside, the function has to be visible from outside. Ideally you would have the self executing function inject it in some passed in context (in this case, this, which references the global context):

(function(context) {
  var foo = function() {
    alert('hello');
  };
  foo();
  context.foo = foo;
})(this);

...

foo();

​ More interesting patterns can be found here.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 1
    It would make more sense to pass `this` since it's guaranteed to reference the global object in global code, `window` isn't guaranteed to reference anything, or even be defined. – RobG Jun 05 '12 at 02:19
  • @RobG: yes, it would :-) I just provided an example and I've explicitly mentioned _some passed in context_. It's up to the OP to decide which context will be best for him. – Jordão Jun 05 '12 at 02:31
  • I notice jQuery 1.7.2 does `(function(window, ... ){...}(window));`, so you're in good (bad?) company. :-) – RobG Jun 05 '12 at 08:32
1

The second function foo is a function definition expression.

In a function definition expression, you can only call the function with the name within the function itself according to "Javascript the definitive guide":

For function definition expressions, the name is optional: if present, the name refers to the function object only within the body of the function itself.

It can be used in a recursion function definition expression.

For example:

var f = function factorial(n) {
    if (n == 0 || n == 1)
        return 1;
    else
        return n * factorial(n-1);
}
zhenguoli
  • 2,268
  • 1
  • 14
  • 31