views:

302

answers:

6

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

A: 

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');
Wesley Mason
But I think he is also trying to create a self-invoking function.
Brian
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.
Wesley Mason
+3  A: 

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
This doesn't answer what he actually wants to do however, which is invoke the anonymous function. See Brian's answer.
Wesley Mason
It explains why it doesn't work, which is EXACTLY what the OP asked.
Philippe Leybaert
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
+3  A: 

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
A: 

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
A: 
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
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.
Török Gábor
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
+5  A: 

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
Thanks kangax - reading your article now! ;-)
Mike Peat