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?

7
  • 1
    I'm not sure if this is the best way to do it. I imagine this will get real messy after a while. Commented Jun 5, 2012 at 0:53
  • 3
    Possible duplicate of stackoverflow.com/questions/6211466/…. Commented Jun 5, 2012 at 0:57
  • Also possible duplicate of stackoverflow.com/questions/6404196/… (which has better answers, IMHO, but the phrasing of the question is less of an exact match.) Commented Jun 5, 2012 at 1:01
  • @apsillers the question is a duplicate but the 1 answer just says to do what I was already doing. Commented Jun 5, 2012 at 1:03
  • @Jake True enough; that's why I posted the second link. Commented Jun 5, 2012 at 1:04

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

11 Comments

Named function expressions should be very useful, but they are broken in IE so recommended against by most. e.g. in the above typeof bar shows "function" even if placed before the IIFE.
@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.
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: 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.)
—unfortunately, more than half of IE web vistors (about 10% of all visitors) are using 8 or lower.
|
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.

2 Comments

+1 No reason this couldn't be done with locals as well. var foo; (foo = func...})()
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.
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.

3 Comments

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: 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.
I notice jQuery 1.7.2 does (function(window, ... ){...}(window));, so you're in good (bad?) company. :-)
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.