Categories

CoffeeScript: Continuing Down the Rabbit Hole

03/26

Spread the word

Functions

Functions are written differently in CoffeeScript than plain JavaScript. Firstly, in CS you cannot do function hello_world() { … } but rather all functions are set to a variable. Next Instead of writing the keyword function we simply use the parentheses to contain our parameters followed by a skinny arrow. (hyphen and greater than symbol) The contents of the function go to the next line and are tabbed in once.

CoffeeScript:

hello_world = () ->
console.log “Hello World"

Compiles to:

var hello_world = function() {
console.log(“Hello World”);
}

Here we can also see that calling console.log(), we do not need the parentheses. This works for any time you are calling a function or method with one or more arguments. Let’s see how this works if we alter hello_world() like so:

Here, because hello_world() now takes two arguments we no longer have to use the parentheses. Yet goodbye_you(), not having any arguments will require them. This is because we don’t want CoffeeScript to decide that goodbye_you is a new variable rather than an already declared function.

Why don’t we go further down the rabbit’s hole here? Look at the goodbye_you() function. What are we missing? Or rather not missing? (enter appropriate level of “lol” here) Because goodbye_you() doesn’t take any arguments we do not need to use the parentheses with the skinny arrow. This might seem intentionally confusing at first, but trust me, once you start get it, you’ll love it.

Sum up:

Declare a function

with parameters -> need parentheses

without parameters -> do not need parentheses

Call a function

with arguments -> do not need parentheses

without arguments -> need parentheses

Another quick note: $ -> is the jQuery $(document).ready(function() { … }); How awesome is that? Look at all those characters that we just don’t have to type anymore.

Variables

You still use var, ew…

In CoffeeScript you do not need to declare a variable with the keyword var

Notice that the compiled JS declares the variable at the very top of its scope without setting a value. So person, x and y are scoped to the document and first_name and last_name are scoped only to the function who_is().

Say what?! That’s right, {first_name, last_name, job} = person will set the variables first_name, last_name and job to attributes set in person with the same names.

Arrays and Objects

Arrays

Arrays are rather standard in CoffeeScript, they are still initiated by square brackets [ ] and each item in the array is separated by a comma.

my_array = [‘Rome’, ‘Carthage’, ‘Syracuse’, ‘Athens’, ‘Alexandria']

Though it should be mentioned that the commas can be omitted from an array if it is written like so:

my_array = [
‘Rome’
‘Carthage’
‘Syracuse’
‘Athens’
‘Alexandria’
]

I have only found this useful when using RequireJS though because it makes all the required attributes easier to read, sort and add to. In the code snippet below we see the define() method takes an argument that it is expecting to be an array. For readability’s sake I put each item on its own line and thus do not need the comma.

Objects

Objects on the other hand benefit greatly from the use of CoffeeScript. I do a lot of BackboneJS which is all Object-Oriented and everything is an object or class. Within this structure these objects are mostly a collection of methods which gets pretty gross in plain JavaScript, but are rather nice and easy to read in CS. Written without the extra curly braces, without commas and forced formatting of CS these objects become quite pleasant to work in.

Please excuse the sudden ancient history in the examples, I was playing Rome Total War 2 just before writing this section.

In this object we can see that I have omitted the commas and am telling CS that a new line with proper tabbing indicates a new attribute. Also there is no need for the opening and closing curly braces. CS knows that the object is done when it reaches destroy_rome() function that has the same amount of tabbing as the person variable.

So let’s take a look at how this helps out with a BackboneJS view that’s in a project using RequireJS.

Looping

Looping in CoffeeScript was one of the trickier aspects that took me a while to wrap my brain around, but once I did it became one of my favorite features of CS. The most used looping method, (at least for me) is comprehensions. The best way to describe a comprehension is thinking of it more like the jQuery or Underscore each method. These each methods iterate through the array or object and run a function (often anonymous) on each of value.

Most of the loops you'll write in CoffeeScript will be comprehensions over arrays, objects, and ranges. Comprehensions replace (and compile into) for loops, with optional guard clauses and the value of the current array index. Unlike for loops, array comprehensions are expressions, and can be returned and assigned.

So what does all this mean? Well we have a function declare_title() that takes one parameter man. CS’s syntax boils down to for every man in the generals array, run declare_title() function and pass the current value.

It’s important to note that declare_title() can also return a value. So if we can mimic the Ruby map() method, which loops through an array or object and generates a new array/object with the altered version of each value.

if name is ‘Hannibal’
alert “#{name} is Carthaginian”
else
alert “#{name} is from somewhere else"

So what about else if? This is done just as you would expect:

if name is ‘Hannibal’
alert “#{name} is Carthaginian”
else if name is ‘Caesar’
alert “#{name} is Roman"
else
alert “#{name} is from somewhere else"

Pretty cut and dry considering what we’ve already learned with CS so far. Now let’s get into unless. If you’ve done any Ruby programing then the concept of unless will be an old hat to you. If not, never fear, it’s a pretty simple concept and extremely useful. unless is just the opposite of if. It runs the specified code if the statement tested returns false. Let’s take a look:

unless name is ‘Caesar'
alert “#{name} lived before the 1st century BC"

One last note about if, else and unless, if you’re like me and really like the ternary method of if/else statements then you will be as disappointed as I was to find out that they do not exist in CoffeeScript. This is the one and only complaint I have with CS and one that I grind my teeth about often.

You can still do your if/else statement on one line, but it requires then and else operators to do so.

greatest_general = if destroy_rome() then “Hannibal” else “Alexander"

A few things you may have noticed that I will go over in the next post.

the is operator

string interpolation

the ? operator

I’m apparently going to cut this into yet another post, because the current one is getting quite long and I don’t want to go forever without posting something. Still to come in the next post: Additional operators, String Interpolation, Switch Statements, Function Binding and much more...