close

Day 5: Add some caffeine to your JS with CoffeeScript

There are a lot of CoffeeScript guides out there. I’ve even written some myself. When I was asked to contribute to the 12 Devs of Xmas with a piece on CoffeeScript, I was keen but knew I needed to take a different angle on it. So I’ve decided that instead of slowly introducing you to CoffeeScript from the base up and writing some typical “Hello World” (does anyone learn from that, really?) I’ve taken a simple piece of JavaScript I’ve written, and together we’ll convert it to CoffeeScript. The original JavaScript and the CoffeeScript rewrite will be available from Github so you can play around to your heart’s content.

Firstly, What is CoffeeScript?

If you know what CoffeeScript is, you could justifiably skip this section and move onto the next. If you’ve no idea what it is, then read on. The best place to enrich your mind is the official CoffeeScript site, which can be found at http://coffeescript.org. CoffeeScript is a small language that compiles into JavaScript and describes itself as: “an attempt to expose the good parts of JavaScript in a simple way”. The code is compiled into regular JavaScript, which can be done in a number of ways (we’ll get to that later). It can solve common JavaScript issues, provide ways to avoid common errors that can really come back to bite you and provides a cleaner syntax.

You will find articles discussing how it’s not worth writing in CoffeeScript, or words to that effect. For some people CoffeeScript is a worthwhile investment of time, and for others it’s perhaps not. This isn’t for me to make you decide; only you and the team you work with can make the decision. What I will say however, is don’t dismiss it without spending some time learning it. Read this guide at least, try writing something of your own in CoffeeScript, and then you can really begin to get a feel for it.

Our Subject Code

The code we’ll be converting into CoffeeScript is something quite basic. I deliberately chose something that’s pretty simple so we can concentrate more on the CoffeeScript side of things. The code I’ve chosen is something I wrote (of course) – it’s a small bit of code to help with responsive design (buzzword alert) and more specifically images. It’s fully open source on Github and it’s this code we’ll be converting. If you’re too lazy to load up Github (it is Christmas after all) then here’s the code in all its glory:

(function(window, document, undefined) {
var responsiveImages = function(elem, options, onResize) {
onResize = onResize || false;
elem = document.getElementById(elem);
var pickImage = function(elem) {
for(var key in options) {
if(key == "else") {
elem.src = options["else"];
break;
} else {
var width = parseInt(key);
var windowWidth = window.innerWidth;
if(windowWidth <= width) {
elem.src = options[key];
break;
}
}
}
}
pickImage(elem);
if(onResize) {
addEvent(window, "resize", function() {
pickImage(elem);
});
}
};
window.responsiveImage = responsiveImages;
//helper function for adding events (used for cross browser onresize method)
var addEvent = function(elem, type, eventHandle) {
if (elem == null || elem == undefined) return;
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
};

})(this, this.document);

The code works by specifying an element and then a number of images to use depending on the width of the browser, like so:

responsiveImage("img", {
"320" : "iPhone.jpg",
"768" : "iPad.jpg",
"1024" : "Average.jpg",
"else" : "HUGE.jpg"
}, true);

We’ll convert it line by line and whenever we meet something new in CoffeeScript that you’ve not come across before, I’ll take a minute to explain it to you fully. Just a word of warning: I am presuming a solid knowledge in JavaScript. If you haven’t worked with JavaScript much before, you should spend more time getting to know JavaScript before returning to CoffeeScript.

Let’s Get Cracking!

Self-Invoking Anonymous Function

The first thing you’ll notice is that we have a self-invoking anonymous function that wraps around all our code and looks something like this:

(function(window, document, undefined) {

})(this, this.document)

This function is called (or invoked) automatically and sets the variables window and document to be equal to this and this.document. It also makes sure the undefined variable is indeed undefined and hasn’t been set to something else. In reality this is perhaps unnecessary, but what it does provide is a nice way to keep all your variables stored together without polluting the global namespace. CoffeeScript, however, automatically wraps our code for us in a similar function:

(function {

}).call(this);

So we don’t have to use a self invoking function, CoffeeScript takes care of it for us.

The addEvent Function

I’m actually going to convert the code in a slightly different order to how it is in the JavaScript file, because in CoffeeScript functions have to be defined before they’re mentioned anywhere else on the page, unlike JavaScript. So although our addEvent function is at the bottom in the JS, I’m going to shift it up to the top so we can reference it in the responsiveImages function, which does most of the work. The addEvent function provides a cross browser function for binding events to elements. Declaring a function in CoffeeScript is a bit more concise than in JavaScript, and declaring the addEvent function looks like this:

addEvent = (elem, type, eventHandle) ->

The first thing to note is that we don’t need to use var – that’s added in for us. Secondly, instead of typing function { we can simply use what I’ve deemed the “dash rocket”, ->. Thirdly, function parameters are denoted before the ->, whereas in JavaScript the function keyword always comes first.

You’re probably wondering where our curly braces are, but we don’t need them. CoffeeScript works on indentation to define blocks in a very similar way to Ruby or Python. The next line of our addEvent function makes sure that the elem variable is actually something we can work with; it’s not null or undefined. In JavaScript we have to do quite a long-winded check:

if (elem == null || elem == undefined) return;

In CoffeeScript we can use the existential operator to do this for us. The existential operator works like so:

if someVar?

Once compiled that code would look like this:

if (typeof someVar !== "undefined" && someVar !== null)

As you can see, that performs the necessary checks for us. However, the existential operator checks if something is null or undefined – what we want to do is check whether something is not undefined or null. So we’ll use CoffeeScript’s not keyword to do that. Now, we could write that statement like this:

if not elem?
return

But that’s two lines, and I prefer the neater one liner:

return if not elem?

You can pre- or postfix if statements in CoffeeScript, along with loops too. Some people prefer one version, whilst others (including yours truly) mix and match depending on the situation. If the code that’s executed if the statement evaluates to true is more than a couple of words, it’s probably worth using the prefix style:

if someStatement
doLotsOfStuff()

In our case however it’s just one word, return, so it feels silly to take up two lines. It comes down to preference really, so I’ll leave the decision up to you.

The next piece of code is another simple if block:

if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}

And this translates pretty straightforwardly into CoffeeScript:

if elem.addEventListener
elem.addEventListener type, eventHandle, false
else if elem.attachEvent
elem.attachEvent "on#{type}", eventHandle

The only piece worth highlighting from this is the last line:

elem.attachEvent "on#{type}", eventHandle

Notice how we can use the #{} syntax (which Rubyists will be familiar with) to output variables to strings. I bet there’s no one more fed up of doing the following over and over again than I am:

"on" + type

CoffeeScript means you never have to, and that’s so nice. For such a small feature, it’s certainly one of my favourites.

The responsiveImage function

So we’re here. We’ve sorted the addEvent function, now it’s time to sort the really important one. This function takes three arguments: an element to work on; the options object which stores widths and the relating image; and a boolean to decide whether to run the code when the window is resized. The first two lines look like this:

var responsiveImages = function(elem, options, onResize) {
onResize = onResize || false;

The second line either sets onResize to equal itself or, if it doesn’t exist, sets it to false, which is essentially saying that the default value for onResize is false. CoffeeScript again has a lovely solution for this – it lets you set a default value in much the same way as many other languages. Here are the first two lines of the function in CoffeeScript, except there’s a catch. It’s now just one line:

responsiveImages = (elem, options, onResize = "false") ->

Fairly self-explanatory, but also very useful. The next line of JS is:

elem = document.getElementById(elem);

And that’s another easy one to change into CoffeeScript. Just drop the brackets and the semicolons:

elem = document.getElementById elem

Now we move onto the pickImage function. This one loops through every key in the options object, and picks the best one depending on the width of the window. We start off by declaring the function (I’m not even going to show you the JS this time, it’s so easy):

pickImage = (elem) ->

Next we need to loop through every key in our object. In JavaScript we use the in keyword to do this:

for(var key in options) {

However in CoffeeScript, the in keyword tests for array presence. For example, to test for the number 5 in an array in CoffeeScript we can do:

5 in [1,2,3,4,5,6,7,8,9]

This means to get at keys in an object, we have to use CoffeeScript’s of keyword. This is one thing I’m not so keen on in CoffeeScript. Personally, I’m not sure that the of keyword is obvious enough in terms of what it does. When I was preparing this article by converting my JS into CoffeeScript I forgot to use of instead of in and it had me stuck for about half an hour. In my opinion, if JavaScript uses the in keyword, there’s no need to remap it and it’s inefficient to do so. Regardless, it’s my only real niggle, so for now we’ll put up with it:

for key of options

Of course, if we wanted to loop through both key and value we could do:

for key, value of items

That would compile into:

for (key in items) {
value = items[key];
}

Now, call me mad, but I’ve always preferred just iterating through keys and getting at the values via:

items[key]

rather than iterating through both keys and values. Again, a personal preference.

Right, back to our pickImage function. Next we need to find out whether the key is “else” and if it is, we can set the image source and we’re done, so we can break out of the loop. Easily done in CoffeeScript:

if key is "else"
elem.src = options["else"]
break

However if the key is not “else”, we have to do some more work. We have to get the integer value of the option, and the width, then set the right image:

else
width = parseInt key
windowWidth = window.innerWidth
if windowWidth <= width
elem.src = options[key]
break

This is pretty simple stuff for someone like yourself, who’s now very used to CoffeeScript.

The final piece of the jigsaw is to call the pickImage function we just wrote, and if onResize is set to true, add an event to call pickImage whenever the window is resized.

pickImage elem
if onResize
addEvent window, "resize", ->
pickImage elem

I said final piece; but we’ve got just one more thing to do. Because CoffeeScript wraps everything in an anonymous function, none of our variables so far have been exposed to the global object (window). It’s easy to do this though; we just declare a new variable on the window object:

window.responsiveImage = responsiveImages

That sets our responsiveImages function to be accessible through window.responsiveImage, which means in our HTML page we can access it like so:

responsiveImage("img", {
"500" : "http://placekitten.com/500/500",
"600" : "http://placekitten.com/600/600",
"700" : "http://placekitten.com/700/700",
"800" : "http://placekitten.com/800/800",
"1000" : "http://placekitten.com/1000/1000",
"else" : "http://placekitten.com/1200/1200"
}, true);

And if you want to check it out you can do, just have a look at the demo page.

Compiling CoffeeScript Files

We’ve come all this way, but as of yet you’ve still got no idea how to compile Coffee files.

Node.js & NPM

If you’ve got Node.js and NPM (Node Package Manager), it’s as easy as:

npm install -g coffee-script

To watch and compile a file every time it’s saved, you can run this command:

coffee --watch --compile example.coffee

That would compile to example.js. There’s a lot more you can do, with documentation on the CoffeeScript site.

If you’re not into the terminal and you’re a Mac user, there are two great apps I know of. The first is called CodeKit and offers a thorough GUI for compiling CoffeeScript files. It also does SASS, LESS, Haml and much more, so it’s well worth checking out. It can also run your code through JSLint and offer tools, as well as minifying files for you too.

Secondly there’s LiveReload 2, an app that automatically monitors a directory and compiles files for you, as well as auto-refreshing the browser. Just like CodeKit, it supports a myriad of formats, not just CoffeeScript, so give it a try. Right now it’s Mac only but there is a Windows version coming in the near future.

If you’re a Windows user, the best I’ve been able to find is a native Command Line tool, CoffeeScript Compiler for Windows. As far as I can tell there’s no GUI app at the moment, but as I mentioned Live Reload is coming to Windows in the future.

Syntax Highlighting

A common issue with pre-processor tools like CoffeeScript is a lack of native syntax highlighting in your text editor / IDE of choice, whether that’s Vim (my tool of choice), Espresso, Coda, Dreamweaver, Notepad++ and so on. Thankfully there’s a very extensive list on the wiki that lists plugins for the vast majority of editors, with all the popular ones included.

Github Repository

The repository for this piece of code can be found on Github, where you’ll find the JS version and the CoffeeScript one we worked through in this article.

Closing Remarks

Looking over a piece of JavaScript and converting it to CoffeeScript was something I’d never done before, and when I was asked to write on CoffeeScript I wanted to avoid the boring step-by-step tutorials we’ve all become accustomed too. This approach (I hope) has given you more of an idea of what it’s like to work on real code in CoffeeScript rather than just listing all the features. Of course I’ve barely scraped the surface, so I highly recommend you check out the official site at coffeescript.org which lists every one of its many features. Ultimately you might decide that it’s not for you, or you might decide you don’t ever want to write JavaScript again. Whatever your decision, I hope this article helped you make it. If you have any questions, please leave a comment and I will respond, or you can tweet me @Jack_Franklin.