Comparing Pre-declared and Self-invoked Anonymous Functions

Go To StackoverFlow.com

1

This is going to be a quick discussion, but I just wanted some feedback on a revelation I had this morning. Knowing that this...

var addTwoNumbers = function(intOne, intTwo) {
    if ((typeof intOne == 'number') && (typeof intTwo == 'number')) {
        document.write(intOne + intTwo);
    } else {
        document.write('Unable to perform operation.');
    }
};

addTwoNumbers(3, 4);

... behaves essentially the same as this...

(function(intOne, intTwo) {
    if ((typeof intOne == 'number') && (typeof intTwo == 'number')) {
        document.write(intOne + intTwo);
    } else {
        document.write('Unable to perform operation.');
    }
})(3, 4);

... is that to say that the first set of parentheses in the self-invoking function is a "tool" to bypass or work around function execution by reference? In effect, () is the name of the method without actually being the name of the method? Also, because the function is being declared directly at execution, is it faster than the technique using a variable name reference? Just wondrin'.

2012-04-05 16:32
by 65Fbef05
Without the outer parentheses, a statement beginning with the keyword function is taken to be a function declaration statement. The parentheses are a way to have the parser recognize the statement as being an expression statement, so that the function keyword will be interpreted in that light instead - Pointy 2012-04-05 16:40
Where this question comes from is my comparison of functionName() vs. ()() - The difference in how the expressions are handled. The bit before the parameter handling parentheses - 65Fbef05 2012-04-05 16:46
Exactly my point. It's just a "trick" to get over the problem that the same keyword is used to start a function declaration statement as is used to instantiate a function object in an expression. You could, instead of putting parentheses around the function, prefix it with "!", since nothing cares about the return value here - Pointy 2012-04-05 16:49
!functionName() {}? I guess I don't follow, could you elaborate with an example - 65Fbef05 2012-04-05 16:51
The ! operator evaluates an expression's logical equivalent (==) - not its strict equality (===) and gives you its opposite, with the side effect of forcing evaluation. If a function returns something, the return value gets evaluated by ! so ! would be a bad way to force-evaluate if your function was meant to assign a return value to a var. If it doesn't return something, a function's logical equivalent is like most things for simply existing in JS, simply true. Examples of stuff with false equivalence in array form: ['',0,undefined,null] Crockford is wrong about '==' being a 'bad part' IMO - Erik Reppen 2012-05-02 16:26
@Erik - Couldn't agree more, and in fact I find myself very seldom even needing strict evaluation. The option to compare type is important, but not always necessary - 65Fbef05 2012-05-02 19:13
@65 - I tend to default to strict (probably higher performing for one thing) but having a more implicit version is nice when things can fail in more than one way. Sometimes I'll start with loose and then do strict comparisons when I want to handle missing data 'undefined' differently from an aborted core operation that I know returns 'null' and that differently from my own validation method that returns 'false' but when things go well, I'd rather success be established first before hitting the fail logic - Erik Reppen 2012-05-02 20:16


3

OK here's the reason that "self-invoking functions" (which really aren't "self-invoking"; there's an explicit invocation and it's outside the function proper) are written (by convention) as a parenthesized subexpression.

JavaScript has two constructs involving the keyword function:

  1. The function declaration statement, which defines a function object and binds it to a name in the local scope (as well as in the function's local scope but let's ignore that for now):

    function foo() { /* code */ }
    
  2. The function instantiation sub-expression, which creates a function object in the context of an expression:

    var f = function() { /* code */ };
    

The problem comes about when you want the second thing, and you want it at the beginning of an expression statement. When the statement starts with the keyword function, the parser assumes that you're doing 1 above, not 2. Thus, by introducing parentheses around the function instantiation — and remember that parenthesizing a sub-expression is always allowed and does not affect its value in any way — makes the use of the function keyword be interpreted as 2 above.

There are other ways of forcing the parser to see the statement as an expression too:

  • !function() { /* code */ }();
  • 0, function() { /* code */ }();
  • +function() { /* code */ }();

are just some examples.

As to performance, it's a non-issue here. One thing I will note is that this way of binding an identifier to a function object:

var name = function() { /* code */ };

is really no better than:

function name() { /* code */ }

and in some ways it's worse. In particular, using a function declaration statement gives a name that will show up in stack traces, while defining the function with var does not.

2012-04-05 17:11
by Pointy
Super-clear explanation, dude. I really appreciate it - 65Fbef05 2012-04-05 17:18
Ads