62

Possible Duplicate:
How do JavaScript closures work?

I was playing around with the Google Closure Compiler, putting in random code to see what it would do.

It rewrote one of my functions to look something like this:

(function(msg) { console.log(msg); })("Hello World!");​​​​​​​

Where it appears that "Hello World" is the argument passed as msg to the anonymous function preceding it. I was looking at it for a moment, and had thought that I had seen something similar in jQuery plugins that look something like:

(function( $ ) {
  ...
})(jQuery); 

Which now makes more sense to me, in the scope of conflicts with $. But what is the primary reason or purpose for passing arguments into an anonymous function like this? Why wouldn't you simply define the arguments as variables within the function? Is there any performance or flexibility advantage to writing functions like this?

Community
  • 1
  • 1
Kyle Macey
  • 8,074
  • 2
  • 38
  • 78
  • For that specific code, there's no real reason. You could just do `console.log("hello");`. But usually it's to create some local variables that are only accessible to some functions that are created inside and exported. – I Hate Lazy Oct 02 '12 at 21:29
  • I'd be curious to see your original code that resulted in that form. I'll bet if you had ADVANCED_OPTIMIZATIONS enabled, it would get rid of the function altogether. – I Hate Lazy Oct 02 '12 at 21:30
  • @user1689607 the function was a bit different and way longer. I made it brief to make it clean on SO. More wondering about the concept than this specific example – Kyle Macey Oct 02 '12 at 21:32
  • Oh, if the question is mainly function parameters vs variables, it's certainly not a performance issue. More likely it's just that it could avoid the `var ` characters in order to reduce the file size. – I Hate Lazy Oct 02 '12 at 21:34
  • If you pass global variable like so, you will be able to change it's name while minifying. Minifying does not rename global variables, so having something like 'MyGlobalVariable.property' will take a lot of space if having 100 occurrences. If you pass it to your anon function and name it even the same inside, minifier will change it's name to e.g. `a` reducing the total size of your app. – Mike Grabowski Nov 11 '14 at 20:32

3 Answers3

22

There is one significant difference connected also to scope. The following code:

(function(msg) { console.log(msg); })("Hello World!");​​​​​​​

is in some circumstances cleaner in terms of namespace pollution than this:

var msg = "Hello World!";
console.log(msg);

because the second code leaves variable after it is no longer needed, but may interfere with other parts of the code.

This is especially important when you execute the mentioned code outside any other function: in such case msg variable would be available everywhere on the page, as global variable.

Tadeck
  • 132,510
  • 28
  • 152
  • 198
  • But how would it be any different then just wrapping your second example in an anonymous function? the variable would still die at the end – Kyle Macey Oct 02 '12 at 21:29
  • I was under the impression he meant something more like this: http://jsfiddle.net/cv5Jp/ – Kevin B Oct 02 '12 at 21:30
  • @KevinB Right, what's the difference between your fiddle and the function I posted? – Kyle Macey Oct 02 '12 at 21:33
  • @ʎǝɔɐɯǝlʎʞ: The argument is still valid in my opinion. The compiler has just chosen `(function(msg){ console.log(msg); })("sth")` instead of `!function(msg){ console.log(msg); }("sth")`, `(function(){ var msg="sth"; console.log(msg); })()` etc. This is very simple example and I would not expect magic behind it, it is just one of the methods to do it. – Tadeck Oct 02 '12 at 21:33
  • @Tadeck I suppose you're right to assume that I expected a bit of magic. Moreso, I was wondering if there was magic there at all, and if this method had any benefit over anything I've been doing – Kyle Macey Oct 02 '12 at 21:35
  • @ʎǝɔɐɯǝlʎʞ: What is the exact code you were using? This may influence the results, and I see that the Google Closure Compiler does not transform `(function(){ var msg="sth"; console.log(msg); })();` into `(function(msg){ console.log(msg); })("sth");`. – Tadeck Oct 02 '12 at 21:40
  • I have the code in a fiddle here: http://jsfiddle.net/coffee_coder/nKZvE/ again, I was just messing around to see what would happen, and shortened my question, not thinking context was tremendously important, though I suppose I ended up wrong – Kyle Macey Oct 02 '12 at 21:44
  • 1
    @ʎǝɔɐɯǝlʎʞ: Ok, now it is obvious. It _is_ about saving unnecessary variables in the global namespace: you are first defining `b()` function, then using it once, and it stays in the global namespace. Thus, the natural way was to change the function into anynymous, self-called function. Adding new argument in the body could result in issues with your code, the compilation was just not so invasive. – Tadeck Oct 02 '12 at 21:48
0

Basically, it's always a good idea to keep your code wrapped in this: (function(){/*code*/}()); to prevent your vars from colliding with other peoples vars.

I think the main thing closure compiler is getting at is saving the 5 characters:var  and =.

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
0

It depends a bit on the context. There are some conditions where the compiler won't try to inline any function at all (if the scoping function contains "eval" for instance). If this is a in global scope and you are running in ADVANCED mode, it is simply that the inlining opportunity appeared after the compiler stop trying to inline functions (or there is a bug in the inlining code and it missed the opportunity). If you run your sample output through the compiler in ADVANCED mode, you get this:

console.log("Hello World!");
John
  • 5,443
  • 15
  • 21