CoffeeScript is a better way to write JavaScript, but it integrates just fine with libraries like jQuery.
Last month, I wrote about CoffeeScript, a new, small language that compiles into JavaScript. CoffeeScript has generated a great deal of buzz and excitement among Web developers, including no less than Brendan Eich, Mozilla's CTO and the inventor of JavaScript. Ruby on Rails 3.1, which presumably will be released by the time this column sees print, includes CoffeeScript, and other frameworks might follow suit in the future.
Even if you're not interested in the future of JavaScript or in Ruby on Rails, you owe it to yourself to look at CoffeeScript. First, it's a new and interesting language, and I'm definitely a believer in learning new languages as part of my professional development. Second, CoffeeScript's syntax makes it easier to do many things that previously were difficult, long-winded or just plain ugly in JavaScript. Just as a number of languages have emerged that compile to the JVM, but that are easier to use in various ways, so too is CoffeeScript functionality equivalent at the end of the day to JavaScript, but with an easier syntax that's more appropriate for many modern applications.
But, perhaps the most interesting part of CoffeeScript is the fact that, ultimately, it's just another way of writing JavaScript, which means anything you can do in JavaScript, you also can do in CoffeeScript. CoffeeScript programs can run on the server, in such environments as node.js, but they also can run in the browser, working in conjunction with Web applications. Things become even more interesting if you use a JavaScript framework, such as jQuery, for developing Web applications—you can benefit from the best of both worlds, enjoying the power and expressiveness of jQuery, along with the terse and readable syntax of CoffeeScript.
This month, I describe some ways that CoffeeScript and jQuery can interact in a browser-based program. Even if you don't decide to adopt CoffeeScript in your own programs, it's worth playing with the language to get the hang of things.
I'm going to assume you already have installed CoffeeScript, as well as any support files, such as a mode for your editor. Create a bare-bones HTML file, as shown in Listing 1, and a stylesheet (coffeescript.css), in the same directory, similar to what's shown in Listing 2. Notice how in the HTML file, I include two JavaScript files:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/ ↪1.4.2/jquery.min.js"></script> <script src="app.js"></script>
The first probably is recognizable as the Google-hosted version of a minified version of jQuery. But the second file, app.js, is the target of the CoffeeScript compilation—that is, you're not going to write app.js directly. Rather, you're going to write CoffeeScript that compiles into JavaScript.
You do this by creating (in the same directory as the HTML file, unless you want to change the paths in the <script> tag) a CoffeeScript program, named app.coffee. Just to test things, I created a very simple CoffeeScript program that uses the standard (and annoying!) alert dialog to say “hello”:
alert "hello"
Save this file as app.coffee. On the command line, you then want to tell CoffeeScript to compile app.coffee into app.js. (Otherwise, it'll try to execute your program, which not only will mean that the resulting JavaScript isn't available for your Web page, but it also will result in an error if you try to access the DOM, which isn't available outside a browser context.) You can do this with:
coffee --compile app.coffee
The problem with this approach is that you need to recompile your CoffeeScript program every time you change it. A better solution probably is to tell CoffeeScript to watch the file and compile it every time a change is detected:
coffee --compile --watch app.coffee
Just after running this, the compiler will run over app.coffee, producing app.js. When you load your Web page, app.js will run, and you should have an alert saying “hello”.
It's important to remember that although CoffeeScript certainly is a different syntax from JavaScript, it is fundamentally the same language. This means any function or object that you can access from JavaScript can be accessed from CoffeeScript, with the same name. True, CoffeeScript does offer some shortcuts and syntactic sugar; those basic JavaScript objects are still around and kicking. That's why you could invoke the “alert” function in app.coffee—it's not that CoffeeScript has defined a new function, but rather that you're using the same built-in JavaScript function.
This means if you load jQuery in the same document as a program written in CoffeeScript, you can use jQuery from within CoffeeScript. What does that mean? Well, it means you can access the jQuery object directly, often abbreviated as $. For example, let's change app.coffee so that it tells you what version of jQuery you're using, normally available via $().jquery. You also can do this in CoffeeScript:
alert $().jquery
Let's do something a bit more exciting now, using jQuery's capabilities for easily changing elements in the DOM based on events that take place. For example, you can add the “large” class to all of the paragraph elements in your document. In JavaScript, you would do this with:
$("p").addClass("large");
In CoffeeScript, you can use the same code as above. But, because CoffeeScript allows you (like in Ruby) to remove most of the parentheses, you end up with this:
$("p").addClass "large"
Notice how the original jQuery selector has remained the same, as has the method you're calling on each of the selected DOM elements. What has changed is the way you invoke the method; you no longer need to put parentheses around it.
There is a problem with this though. It will execute immediately upon being loaded. The problem is that just because the JavaScript is executing, it doesn't mean the HTML all has been loaded or rendered onto the screen. Now, you can get around this in traditional jQuery by putting all of your code inside a call to $(document).ready(), as in:
$(document).ready( function () { // Event handlers go here } );
You can do the same thing, but in less space (of course) using CoffeeScript:
$(document).ready -> ($ "p").addClass "large"
As you can see, CoffeeScript's syntax is cleaner and trimmer, without nearly as many curly braces and parentheses. You start off with the same invocation of $ with the “document” parameter, and then invoke the “ready” method on that object. You then need to pass a function to “ready”, which you do, by defining a new, anonymous method with CoffeeScript's -> symbol, cleverly dubbed “dashrocket” in the PeepCode screencast about CoffeeScript.
In other words, you've wrapped your original invocation of “addClass” and friends inside a function that's invoked when the document is ready. But, you've cut the number of lines of code in half, without sacrificing readability. Now, let's do something a bit more exciting, namely change the size each time you click on a paragraph. In order to do that, you'll need to use one of jQuery's event handlers—specifically, you'll use the “click” handler, which you set by invoking a selector, the “click” method, and then passing the name of a function. For example, if all you want to do is display an alert dialog when a paragraph is clicked, you can do it with the following CoffeeScript:
$(document).ready -> changeSize = -> alert("changing size!") $("p").addClass "large" $("p").click changeSize
Note how I've defined two functions here: an anonymous function for $(document).ready and another function to which I give the name changeSize. But, of course, you want to do something a bit more complex than display an alert dialog; you want to change the size. When changeSize is fired, you want to know which paragraph to change. An event handler always is passed “this”, an all-too-common word in JavaScript that confuses many people.
One way to get the sizes to rotate is shown in Listing 3, app.coffee. Basically, your callback function starts off by assigning a local variable, “text”. If this were JavaScript, “text” would not be a local variable, but rather a global one, because you used neither the “var” keyword nor another object (for example, myObject.text). In CoffeeScript, variables are local, which means you cannot pollute the global namespace accidentally.
Listing 3 shows a basic use of if/then/else blocks. Notice there isn't any need for braces, begin/end statements or other markers. Python programmers will see this (rightly) as a vindication of semantically significant whitespace. I just like the fact that well-indented code is easy to read, and that CoffeeScript enforces this on me.
You also can see that with rare exception, you've managed to get rid of the parentheses that JavaScript would require, in favor of terse, clean syntax. You're still using the same jQuery methods, but you're doing so in a way that I find easier to read.
You then take the changeSize function and attach it to an event:
($ "p").click changeSize
It might look a bit strange to have the parentheses around the call to $ "p", which in standard jQuery would look like:
$("p")
CoffeeScript tries to get rid of as many parentheses as possible, but there are times when the ambiguity would makes things too difficult for its parser. In such circumstances, you can use parentheses to make things easier.
As you can see from the above example, CoffeeScript makes all of jQuery's functions available. No matter what you might want to do to the text or HTML of your document, you can use CoffeeScript to do it—adding and removing (and querying) nodes, adding and removing (and querying) attributes, changing text, invoking menus or anything else you can do in JavaScript. Having jQuery around means you can make use of its syntax and abstractions, a potentially killer combination. Indeed, a number of blog postings (including several mentioned in the Resources section for this article) indicate that the combination of CoffeeScript and jQuery is a popular and effective one.
jQuery is a popular framework for client-side Web development, providing a large number of abstractions and convenience functions for querying and modifying the DOM. CoffeeScript is a language that makes it easier to write in JavaScript, by simplifying the syntax, removing some of the most common problems that people have with the language, and providing easier ways to work with strings, arrays and hashes. But at the end of the day, both jQuery and CoffeeScript are tools for working with JavaScript, which means there's full interoperability between them. Although the examples in this column are simple, they demonstrate that it's easy to get started with CoffeeScript and even to integrate it into an existing application. My guess is that CoffeeScript has a very bright future and, I should add, deservedly so.