This is good, popular and recommended to wrap every JS file in an anonymous closure function:
(function (){ // (a)
var module_wide_var = 0; // (1)
function inc() { module_wide_var += 1; return module_wide_var; } // (2)
function dec() { module_wide_var -= 1; return module_wide_var; }
window.inc = inc; // (3)
window.dec = dec;
}()) // (b)
|
|
(function (){ // (a)
var module_wide_var = 0; // (1)
function inc() { module_wide_var += 1; return module_wide_var; } // (2)
function dec() { module_wide_var -= 1; return module_wide_var; }
window.inc = inc; // (3)
window.dec = dec;
}()) // (b)
|
Here we:
- (1) define a “global” variable,
- (2) define a couple of functions
- (3) expose our functions through the true global window object,
and everything is wrapped in an anonymous function (a), that’s instantly executed (b).
This approach implements the module pattern (well, in this case not clearly).
The whole function definition and invocation statement is wrapped in parens, because otherwise browsers fail to handle it as function expression.
There’s also 2 possible syntax for invocation – you can put it like (function (){ ... })() or (function (){ ... }()). I prefer the latter as recommended by Crockford (check for yourself).
OK, then, finally, a tiny point we forgot here: the trailing semicolon is the must.
The script above would work without any questions, until you try concateneting two of the kind. And for any big ptoject you’ll most probably have scripts compression and combining.
So, let’s see what happens:
(function (){ /* file 1 */ }())
(function (){ /* file 2 */ }())
|
|
(function (){ /* file 1 */ }())
(function (){ /* file 2 */ }())
|
The 1st line is result of compressing the 1st file, the 2nd line, accordingly, represents the 2nd file. Now, see: the 2nd line is wrapped in parens (and it has to be), and from the JS point of view it immediately follows the 1st line, i.e. the code is equivalent to
(function (){ /* file 1 */ }())(function (){ /* file 2 */ }())
|
|
(function (){ /* file 1 */ }())(function (){ /* file 2 */ }())
|
There’s no automatic semicolon insertion here.
This snippet is interpreted as function application, where the 1st part ((function (){ /* file 1 */ }())) is expected to return the function (we know, it returns undefined indeed), then parens follow, and inside them there’s function (){ /* file 2 */ }() that’s interpreted as the function argument.
What’s the problem? Well, the 1st part doesn’t return function, and the whole expression fails. With semicolons it would look like
(function (){ /* file 1 */ }());
(function (){ /* file 2 */ }());
|
|
(function (){ /* file 1 */ }());
(function (){ /* file 2 */ }());
|
which clearly represents 2 separate expressions.
Even if you’re a good boy, you can be punished because of other’s lazyness
I always use anonymous closure for my scripts, and I always put the trailing semicolon. But because of other developer’s lazyness I encountered this error and was relly frustrated until I realized what happened.
Our project included the already minimized code of one jQuery plugin. For some reason (I’m not really interested) this code looked like
/* copyright and license comment */
eval(function(p,a,c,k,e,r){...})
|
|
/* copyright and license comment */
eval(function(p,a,c,k,e,r){...})
|
This script was compressed with packer, and packer doesn’t care about anything that can follow its results – no semicolon there.
So, followed by my anon-closure-wrapped code, the 2 files combined were interpreted as a function execution, which, of course, failed.