The gems of CoffeeScript
Ever since I got introduced to CoffeeScript it's been a joy to use. The lean syntax makes for readable code without some of JavaScripts quirks but maintaining all of it's power. There is a long list of CoffeeScript features which you can browse on the coffeescript.org website. In this post I'd like to highlight some of the gems in the language that make me use it. This in no way a guide to using CoffeeScript and it is certainly not complete reference.
For people who don't know Coffeescript: it is a syntax build on top of JavaScript in an attempt to expose the good parts of JavaScript in a simple way. It has one golden rule: "It's just JavaScript". This means Coffeescript will compile down to readable JavaScript which makes it usable in existing projects or environments.
Syntax
Coffeescript has a leaner syntax opposed to JavaScript, leaving away certain syntax elements in favor of simplicity and readability. Coffeescript is whitespace significant and uses this to delimit blocks of code. This makes curly braces unnecessary and in some cases optional. The same goes for semicolons. These are only required when putting multiple expressions on a single line.
Functions
Functions are far easier to declare than in plain JavaScript. The syntax is just that simple: a pair of parenthesis with parameters, an arrow and you're good to go. The function body is defined by indentation.
shout = (message) ->
console.log message + "!!!"
shout "Hello World"
This will compile down to something like this:
var shout;
shout = function(message) {
console.log(message + "!!!";
};
shout("Hello World");
Functions are called without parenthesis with just a listing of the parameters. The CoffeeScript compiler will detect function calls by the list of parameters, even when there are nested function calls. When you need to call a function without parameters you can use the special do keyword. Using this keyword do someFunc then becomes someFunc().
Objects
Object notation is stripped from curly braces, which makes it look something like YAML. If each property from the object is listed on a separate line the semicolons can also be skipped. The syntax still allows nested objects as long as the indentation is correct:
heroes =
superman:
name: "Clark Kent"
job: "Reporter"
spiderman:
name: "Peter Parker"
job: "Photographer"
batman:
name: "Bruce Wayne"
job: "Entrepreneur"
Personally I find this syntax to be confusing sometimes, especially with short objects. The nice thing is however that you don't need to worry about missing braces or semicolons since they are optional. You can choose to include them if it makes it more readable for you and not worry about errors when you missed one.
Classes and inheritance
One of the trickiest things in JavaScript is the creation of objects and dealing with prototypes. Even though JavaScript does not have classes Coffeescript supports a class and extends keyword to help with these.
class Animal
constructor: (@name, @legs) ->
describe: () ->
return "this a #{@name} with #{@legs} legs"
class Monkey extends Animal
constructor: (@type = "Unknown") ->
super "Monkey", 4
gorilla = new Monkey "Gorilla"
do gorilla.describe
Working with objects in CoffeeScript becomes very easy, especially when you look at the amount of code that is generated by the compiler. Besides the easy inheritance with the class, extends and super keywords there are two other features that make CoffeeScript classes even more convenient.
The @ symbol represents the currently bound this variable within classes. All variables starting with the symbol will be converted to a variables on the this object. The symbol becomes even more powerful when used with function parameters. If function parameters begin with the @ symbol they are directly bound to the object without any extra code. This is a powerful feature because the bound parameters are easily spotted in the function signature, it saves time in writing function bodies and makes renaming parameters very quick.
Even more time can be saved on function bodies with default parameter values that CoffeeScript allows in the function signature. This saves you from writing those big chunks of code at the beginning of a function to check all the parameters.
If you want to see the CoffeeScript compiler output for the above classes I recommend playing around with the "Try CoffeeScript" button on the coffeescript.org website.
Function binding
The this value is dynamically bound in JavaScript and it is easy to lose track of it. It is even more work to make sure to bind it properly to your nested function calls, not an uncommon situation in JavaScrip. CoffeeScript has a simple syntax to help with this. Instead of using a simple arrow (->) in the function signature you can use a fat arrow (=>) to have CoffeeScript automatically bind the current this scope to the new functions.
Customer = (@name, @account) ->
$('.checkout').click (event) =>
@account.charge amount
The fat arrow allows the embedded function to have the scope of the function it was defined in and to use it's variables. This is my favorite CoffeeScript feature because it makes complex situation so straightforward.
Destructuring assignment
Extracting values from arrays or objects is made more convenient by CoffeeScripts implementation of ECMAScript Harmony's proposed destructuring assignment syntax. With this syntax it is utterly simple to retrieve values from function returns.
[firstName, lastName] = "Mattijs Hoitink".split " "
String interpolation
This would probably be my other favorite feature. Not because it I use it that much but just because it obvious and it feels like it should work this way. Variables can be used within CoffeeScript string with a simple syntax.
name = "Mattijs"
console.log "Hi, my name is #{@name}"
Conclusion
CoffeScript has some great features that really make it worthwhile to use it, especially with large projects. I do however still value plain JavaScript and I still recommend to read up on the problems CoffeeScript tries to solve. CoffeeScript is not the solution to those problems, it merely a different way of describing the solutions. If you are not familiar with these problems you can still find yourself ending up in weird situations.