3

Can anybody explain why this works:

var sayHello = function (name) {
   alert("Hello there " + name + "!");
}("Mike");

While this does not:

function sayHello (name) {
   alert("Hello there " + name + "!");
}("Mike");

Mike Peat

Mike Peat
  • 415
  • 1
  • 6
  • 14
  • Thanks guys - I'm not actually trying to get this to work, but rather I am writing a JavaScript course in which I am trying to give the students as good an understanding as I can get to about what is actually going on. My understanding (possibly flawed!) was that: function foo () {} was just shorthand for: var foo = function () {} and that all JavaScript functions were *really* anonymous, but that we had references to them, which is why the fact that one form worked but the other didn't perplexed me. What I was really aiming for was the even more radical: function () {} (); – Mike Peat Aug 19 '09 at 11:21

6 Answers6

13

All you have to understand here is the difference between FunctionExpressions and FunctionDeclarations in Javascript.

When you surround function with parenthesis -

(function sayHello (name) {
   alert("Hello there " + name + "!");
})("Mike");

- you, technically, apply a grouping operator to it. Once applied, overall production is no longer a FunctionDeclarataion, but a FunctionExpression. Compare -

function foo(){ } // FunctionDeclaration

(function foo(){ }); // FunctionExpresson
typeof function(){ }; // FunctionExpression
new function(){ }; // FunctionExpression

FunctionExpression (contrary to FunctionDeclaration), just like any other MemberExpresson can be appended with Arguments ("(" and ")") and will result in function invocation. This is exactly why function is being called in your first example and not in a second.

Note that FunctionExpressions are allowed to have optional Identifiers (contrary to FunctionDeclarations which must always have one), so you can easily omit "sayHello" and end up with so-called anonymous function expression -

(function(){
  alert('...');
});

You can check out my article on named function expressions, which delves into subtle details of difference between function expressions and function declarations in much more detail.

kangax
  • 37,379
  • 12
  • 94
  • 132
  • It seems as your article link is broken. (Therefore) Some additional resources: http://kangax.github.com/nfe/ , http://stackoverflow.com/questions/1013385/what-is-the-difference-between-a-function-expression-vs-declaration-in-javascrip , http://stackoverflow.com/questions/939386/javascript-immediate-function-invocation-syntax , http://my.safaribooksonline.com/book/programming/javascript/9781449399115/functions/immediate_functions – SunnyRed Jan 27 '12 at 17:53
4

Your second code is actually:

function sayHello (name) {
   alert("Hello there " + name + "!");
}

("Mike");

So you are first declaring function "sayHello", and then you're executing the "statement":

("Mike");

which does nothing.

Philippe Leybaert
  • 155,903
  • 29
  • 200
  • 218
  • This doesn't answer what he actually wants to do however, which is invoke the anonymous function. See Brian's answer. – Wes Mason Aug 19 '09 at 11:04
  • 1
    It explains why it doesn't work, which is EXACTLY what the OP asked. – Philippe Leybaert Aug 19 '09 at 13:18
  • Philippe - that is correct I think, but what I was failing to see is that in the first form, the assignment of the lambda to the var *should* actually be semi-colon terminated (a fact disguised by the braces of the function body), which lack is what allows the ("Mike") to invoke the function. Is that right do you think? – Mike Peat Aug 19 '09 at 14:50
3

This will work:

    (function sayHello (name) {
        alert("Hello there " + name + "!");
     })("Mike");

Notice the parens wrapping the function itself. You can also remove the function name "sayHello" and it will still work. As far as why? I'm not positive. Maybe its that by assigning it to a variable and not using the wrapping ()'s, you are actually assigning it to sayHello and then executing on say hello, not the anonymous function.

Brian
  • 3,921
  • 7
  • 38
  • 69
1
var sayHello = function (name) {
   alert("Hello there " + name + "!");
}("Mike");

This creates an anonymous function and calls it right away with the "Mike" parameter. Then the return value of that function call is assigned to the variable sayHello.

function sayHello (name) {
   alert("Hello there " + name + "!");
}("Mike");

This just defines a normal function with the name sayHello and the function statement ends after the closing }. Then follows the ("Mike") statement which is valid, but does nothing.

port-zero
  • 617
  • 3
  • 7
  • There is no ‘normal’ function. `function sayHello() {}` is only a shorthand for `var sayHello = function() {}`. See Crockford's *JavaScript: The Good Parts* for further references. – viam0Zah Aug 19 '09 at 11:01
  • Ah! But this is helping me understand! function foo() () may /effectively be/ shorthand for var foo = function () {}, but the former is function statement, while the latter is the assignment of the result of a function statement to a variable. I think I *might* be getting clearer on this! ;-) (But I'm not /quite/ there yet!) – Mike Peat Aug 19 '09 at 11:36
0

Edited because my answer had incorrectly read the original post:

As your function is no longer being assigned as a lambda function to a value, invoking the function afterwards with ("Mike") won't work as there's no value to invoke the call on. As others suggested wrapping this with parenthesis to create a temporary variable will still let you invoke the anonymous function:

(function sayHello (name) {
   alert("Hello there " + name + "!");
})('Mike');
Wes Mason
  • 1,521
  • 11
  • 13
  • But I think he is also trying to create a self-invoking function. – Brian Aug 19 '09 at 10:57
  • Ah yes, this is correct..which won't work in this context because it's never being assigned to a value to then invoke. My bad. Will edit. – Wes Mason Aug 19 '09 at 11:02
0

Surrounding the function definition in () before calling it works:

(function sayHello(name) {
   alert("Hello there " + name + "!");
})("Mike");

// however -- 
alert(typeof sayHello);  // undefined

So if you want to do something like that - you might as well just make it an anonymous function:

(function(name) {
   alert("Hello there " + name + "!");
})("Mike");

And I'm not sure it's required - but for safety - anytime I'm using a closure like that I always wrap it in ()

gnarf
  • 101,278
  • 24
  • 124
  • 158