Pattern for CoffeeScript modules [duplicate]
Solution 1:
Harmen's answer is quite good, but let me elaborate a bit on where this is done by the CoffeeScript compiler and why.
When you compile something with coffee -c foo.coffee
, you will always get a foo.js
that looks like this:
(function() {
...
}).call(this);
Why is that? Well, suppose you put an assignment like
x = 'stringy string'
in foo.coffee
. When it sees that, the compiler asks: Does x
already exist in this scope, or an outer scope? If not, it puts a var x
declaration at the top of that scope in the JavaScript output.
Now suppose you write
x = 42
in bar.coffee
, compile both, and concatenate foo.js
with bar.js
for deployment. You'll get
(function() {
var x;
x = 'stringy string';
...
}).call(this);
(function() {
var x;
x = 42;
...
}).call(this);
So the x
in foo.coffee
and the x
in bar.coffee
are totally isolated from one another. This is an important part of CoffeeScript: Variables never leak from one .coffee file to another unless explicitly exported (by being attached to a shared global, or to exports
in Node.js).
You can override this by using the -b
("bare") flag to coffee
, but this should only be used in very special cases. If you used it with the above example, the output you'd get would be
var x;
x = 'stringy string';
...
var x;
x = 42;
...
This could have dire consequences. To test this yourself, try adding setTimeout (-> alert x), 1
in foo.coffee
. And note that you don't have to concatenate the two JS files yourself—if you use two separate <script>
tags to include them on a page, they still effectively run as one file.
By isolating the scopes of different modules, the CoffeeScript compiler saves you from the headache of worrying whether different files in your project might use the same local variable names. This is common practice in the JavaScript world (see, for instance, the jQuery source, or just about any jQuery plugin)—CoffeeScript just takes care of it for you.
Solution 2:
The good thing about this approach is that it creates private variables, so there won't be any conflict with variable names:
(function() {
var privateVar = 'test';
alert(privateVar); // test
})();
alert(typeof privateVar); // undefined
The addition of .call(this)
makes the this
keyword refer to the same value as it referred to outside the function. If it is not added, the this
keyword will automatically refer to the global object.
A small example to show the difference follows:
function coffee(){
this.val = 'test';
this.module = (function(){
return this.val;
}).call(this);
}
var instance = new coffee();
alert(instance.module); // test
function coffee(){
this.val = 'test';
this.module = (function(){
return this.val;
})();
}
var instance = new coffee();
alert(typeof instance.module); // undefined
Solution 3:
This is similar syntax to this:
(function() {
}());
which is called an immediate function. the function is defined and executed immediately. the pros to this is that you can place all of your code inside this block, and assign the function to a single global variable, thus reducing global namespace pollution. it provides a nice contained scope within the function.
This is the typical pattern i use when writing a module:
var MY_MODULE = (function() {
//local variables
var variable1,
variable2,
_self = {},
etc
// public API
_self = {
someMethod: function () {
}
}
return _self;
}());
not sure what the cons might be exactly, if someone else knows of any i would be happy to learn about them.