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)
1 2 3 4 5 6 7 8 9 |
(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 */ }())
1 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 */ }())
1 |
(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 */ }());
1 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){...})
1 2 |
/* 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.
> 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.
This is why many plugins start and end with a semicolon:
;(function (){ /* file 1 */ }());
yes, that makes a lot of sense – you can never know
There’s really no reason one would have to place initial semicolons or trailing semicolons in a file. If your build tool is concatenating your JavaScript files without taking into account the parsing of such files, it’s already doing it wrong.
None-the-less, there are other ways of forcing the parser to parse something as an expression that doesn’t imply a statement continuation:
void function(){ /* ... */ }()
!function(){ /* ... */ }()
+function(){ /* ... */ }()
-function(){ /* ... */ }()
0,function(){ /* ... */ }()
'@exec',function(){ /* ... */ }()
( ... )
Other than that, I don’t get why people would force a function expression where the parser already expects an expression, which more often than not cause the code to be very cluttered:
var x = (function(){ return 'foo' })()
// is the same as
var x = function(){ return 'foo' }()
Anyways, if your library code is breaking because missing semicolons, the problem is not in your code, it’s in the building tool…
I cannot agree.
If you are using immediately executing anonymous function, you have to put semicolon if you care about valid JS.
And I think you mix concatenation and code optimization. Yes, I can agree that google Closure approach to code optimization is probably the most powerful. But scripts concatenation is a separate trivial task, and you should understand that your plugin could (and most probably would) be concatenated. You should, have to and must write valid good code, and it automatically solves the problem I’m talking about.