views:

3381

answers:

7

Hello JS experts!

I'm reading some posts about closures and see this stuff all over the places, but there is no explanation how does it works - just every time I'm told to use it...:

// Create a new anonymous function, to use as a wrapper
(function(){
    // The variable that would, normally, be global
    var msg = "Thanks for visiting!";

    // Binding a new function to a global object
    window.onunload = function(){
        // Which uses the 'hidden' variable
        alert( msg );
    };
// Close off the anonymous function and execute it
})();

Ok I see that we will create new anonymous function and then execute it. So after that this simple code should work (and it does):

(function (msg){alert(msg)})('SO');

My question is what kind of magic come to place here? I thought that when I wrote:

(function (msg){alert(msg)})

then new unnamed function will be created like function ""(msg) ...

but then why this does not work?

(function (msg){alert(msg)});
('SO');

Why it need to be in the same line?

Could please point me the the some post or give me the explanation?

+16  A: 

Drop the semicolon after the function definition.

(function (msg){alert(msg)})
('SO');

Above should work.

DEMO Page: http://jsbin.com/ujazi

Code: http://jsbin.com/ujazi/edit

I have discussed this kind of pattern in this post:

http://stackoverflow.com/questions/1122690/jquery-and-questions/1122740#1122740

EDIT:

If you look at ECMA script specification, there are 3 ways you can define a function. (Page 83, Section 13 Function Definition)

1. Using Function constructor

var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30

2. Using Function declaration.

function sum(a, b)
{
    return a + b;
}

alert(sum(10, 10)); //Alerts 20;

3. Function Expression

var sum = function(a, b) { return a + b; }

alert(sum(5, 5)); // alerts 10

So you may ask, what's the difference between declaration and expression?

From ECMA Script specification:

FunctionDeclaration : function Identifier ( FormalParameterListopt ){ FunctionBody }

FunctionExpression : function Identifieropt ( FormalParameterListopt ){ FunctionBody }

If you notice, 'identifier' is optional for function expression. And when you don't give an identifier, you create an anonymous function. It doesn't mean that you can't specify an identifier.

This means following is valid.

var sum = function mySum(a, b) { return a + b; }

Important point to note is that you can use 'mySum' only inside the mySum function body, not outside. See following example:

var test1 = function test2() { alert(typeof test2); }

alert(typeof(test2)); //alerts 'undefined', surprise! 

test1(); //alerts 'function' because test2 is a function.

Live Demo

Compare this to

 function test1() { alert(typeof test1) };

 alert(typeof test1); //alerts 'function'

 test1(); //alerts 'function'

Armed with this knowledge, let's try to analyze your code.

When you have code like,

    function(msg) { alert(msg); }

You created a function expression. And you can execute this function expression by wrapping it inside parenthesis.

    (function(msg) { alert(msg); })('SO'); //alerts SO.
SolutionYogi
Yeah, but why? Why it need to be as an inline? No matter how many white space I will use.
palig
As I wrote, the semi-colon terminated the anonymous function definition. Because it has no name (it's anonymous duh!), you won't be able to call it anymore. If you don't put semicolon then function could still be executed.
SolutionYogi
It does work. Try this. http://jsbin.com/ujazi
SolutionYogi
I thought that automatic semicolon insertion would put a semicolon in in this case, but it doesn't. So you're right.
Nosredna
Nosredna, JS behaves little arbitarily when it comes to adding semi colons. Read this detailed article: http://blog.boyet.com/blog/javascriptlessons/javascript-for-c-programmers-magic-semicolons/
SolutionYogi
Yes I see that (function (msg){alert(msg)})('SO'); works. I was just asking why does it work. Where this is specified or what kind of JS feature this is. So once I just call: (function (msg){alert(msg)}) what will happen with the function? It will be GC'ed?
palig
I would like to think that it will be GCed as and when browser decides. But you do lose the ability to use the function.
SolutionYogi
palig, I updated my answer with more details about JS function. Hope that helps.
SolutionYogi
`alert(typeof test1); //alerts 'test1'` No it doesn't. `typeof test1 == "function"`
Justin Johnson
That's a typo, will correct it. I hope you got the main message though. :)
SolutionYogi
Ok great update! Here is now all I need to know on the one place.Many thanks!
palig
I may be mistaken, but I'm pretty sure IE treats named function expressions as function declarations as well, so you can call the function by name outside of the function itself. So in your example, `mySum` would be defined even outside the function block. I'm not positive about that, but either way, IE has some weird bugs with function declarations. :)
musicfreak
+9  A: 

It's called a self-invoked function.

What you are doing when you call (function(){}) is returning a function object. When you append () to it, it is invoked and anything in the body is executed. The ; denotes the end of the statement, that's why the 2nd invocation fails.

There's a good article about the pattern here. I'm sure there are others.

seth
Ah ok I see, so it's just some special JS' syntax, right?Like this explanation the most! Simple and short :)
palig
I think it's incorrect to say that the body will be 'evaled'. It executes just like any other function. Because it is anonymous, either you to save the reference somewhere OR execute it right away.
SolutionYogi
Personally, I don't even like the term 'self invoking function'. It's not that function is invoking itself. The programmer wrote those parenthesis to invoke it.
SolutionYogi
@SolutionYogi -- good point. updated the text.
seth
It's not "special syntax" more than anything else is special. Actually, the "function name (args) { BLOCK }" form is much more "special". It is actually unnecessary sugar; this, though, is what actually makes things happen.
jrockway
jrockway why is that other code block special? Care to elaborate?
SolutionYogi
+2  A: 

It's just how Javascript works. You can declare a named function:

function foo(msg){
   alert(msg);
}

And call it:

foo("Hi!");

Or, you can declare an anonymous function:

var foo = function (msg) {
    alert(msg);
}

And call that:

foo("Hi!");

Or, you can just never bind the function to a name:

(function(msg){
   alert(msg);
 })("Hi!");

Functions can also return functions:

function make_foo() {
    return function(msg){ alert(msg) };
}

(make_foo())("Hi!");

It's worth nothing that any variables defined with "var" in the body of make_foo will be closed over by each function returned by make_foo. This is a closure, and it means that the any change made to the value by one function will be visible by another.

This lets you encapsulate information, if you desire:

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

It's just how nearly every programming language but Java works.

jrockway
A: 

Becouse you define a lambda function, and immediatly call it, and passing the string 'SO' to it. Drop the semicolon, as Yogi said.

erenon
+3  A: 

The code you show,

(function (msg){alert(msg)});
('SO');

consist of two statements. The first is an expression which yields a function object (which will then be garbage collected because it is not saved). The second is an expression which yields a string. To apply the function to the string, you either need to pass the string as an argument to the function when it is created (which you also show above), or you will need to actually store the function in a variable, so that you can apply it at a later time, at your leisure. Like so:

var f = (function (msg){alert(msg)});
f('SO');

Note that by storing an anonymous function (a lambda function) in a variable, your are effectively giving it a name. Hence you may just as well define a regular function:

function f(msg) {alert(msg)};
f('SO');
Stephan202
+3  A: 

An anonymous function is not a function with the name "". It is simply a function without a name.

Like any other value in Javascript, a function does not need a name to be created. Though it is far more useful to actually bind it to a name just like any other value.

But like any other value, you sometimes want to use it without binding it to a name, that's the self-invoking pattern.

Here is a function and a number, not bound, they do nothing and can never be used:

function(){ alert("plop"); }
2;

So we have to store them in a variable to be able to use them, just like any other value:

var f = function(){ alert("plop"); }
var n = 2;

You can also use a syntatic sugar to bind the function to a variable:

function f(){ alert("plop"); }
var n = 2;

But if naming them is not required and would lead to more confusion and less readability, you could just use them right away.

(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5

Here, my function and my numbers are not bound to a variable but still can be used.

Said like this, it looks like self-invoking function have no real value. But you have to keep in mind that Javascript scope delimiter is the function and not the block ({}).

So a self-invoking function actually has the same meaning as a C++, C# or Java block. Which means that variable created inside will not "leak" outside the scope. This is very useful in Javascript in order not to pollute the global scope.

Vincent Robert
Nice post. What will then happen with the 'function(){ alert("plop"); }' when I did execute it? It will be GC'ed?
palig
+1 for pointing out the scope issue. Nasty, nasty issue.
Tom Hubbard
The function(){ alert("plop"); } instruction just allocates the function but does not execute it nor binds it to a variable. Since the created function is not bound to any variable, it will be quickly GCed.
Vincent Robert
+1  A: 

This answer is not strictly related to the question, but you might be interested to find out that this kind of syntax feature is not particular to functions. For example, we can always do something like this:

alert(
    {foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"

Related to functions. As they are objects, which inherit from Function.prototype, we can do things like:

Function.prototype.foo = function () {
    return function () {
        alert("foo");
    };
};

var bar = (function () {}).foo();

bar(); // alerts foo

And you know, we don't even have to surround functions with parenthesis in order to execute them. Anyway, as long as we try to assign the result to a variable.

var x = function () {} (); // this function is executed but does nothing

function () {} (); // syntax error

One other thing you may do with functions, as soon as you declare them, is to invoke the new operator over them and obtain an object. The following are equivalent:

var obj = new function () {
    this.foo = "bar";
};

var obj = {
    foo : "bar"
};
Ionuț G. Stan