Pattern for CoffeeScript modules [duplicate]

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.

Leave a Comment