Screencasts

Introduction to CoffeeScript

Show Notes

With the adoption of CoffeeScript by the Node.js community, the JavaScript community in general, and with CoffeeScript's inclusion in the upcoming Rails 3.1 release, it's probably a good idea to see what all the fuss is about.

In this free CoffeeScript screencast we'll cover all the basics and some neat features that will make the writing of complex JavaScript a thing of the past.

Links

CoffeeScript Documentation

What You'll Learn

How to install and use CoffeeScript How to use the standard types in CoffeeScript How to write functions in CoffeeScript How to write classes in CoffeeScript

Script

Welcome to the Introduction to CoffeeScript screencast. With the adoption of CoffeeScript by the Node.js community, the JavaScript community in general, and with CoffeeScript's inclusion in the upcoming Rails 3.1 release, it's probably a good idea to see what all the fuss is about.

What is CoffeeScript?

CoffeeScript is a language that compiles down to JavaScript. This means that code in .coffee files are not interpreted at run time, but are compiled beforehand into .js files.

CoffeeScript can be written for all implementations of JavaScript, whether it's for Node.js or the browser.

Why CoffeeScript?

First of all, JavaScript got a bad wrap in the past for the copy-and-paste mentality of the 90's and early 2000's, where no one really knew what was going on. But JavaScript as a language really is great and has a lot to offer.

Saying that, you can get lost in the curly brackets and semi-colons - It can get messy, and sometimes a tad unreadable.

CoffeeScript gets around these issues by adding "syntactic sugar", similar to what Ruby and Python have to offer, which helps us write less code faster, which is also easier to read. Even when it's compiled down, CoffeeScript performs as well as JavaScript, and in some instances the compiled JavaScript has even better performance over hand-written code, due to optimizations CoffeeScript uses that some people may not be aware of. You can actually learn a lot about JavaScript by looking at what CoffeeScript compiles down to, so we encourage you to do that, and ask why CoffeeScript has done things a particular way.

Installing CoffeeScript

To install CoffeeScript we're going to use Homebrew. If you're unfamiliar with Homebrew, we encourage you to check out our How to Use Homebrew screencast to get up to speed.

First, let's update Homebrew to make sure we have the latest formula for CoffeeScript. We do this by typing brew update.

Next, we'll install CoffeeScript. The formula name is coffee-script so let's brew install coffee-script. As you can see, node.js is a dependency for the coffee-script formula, so this install may take some time.

OK, now let's check to see if the latest CoffeeScript has been installed correctly. We'll do this by typing coffee -v.

CoffeeScript Usage

You can use the coffee command in various ways. We'll show you a couple ways you can get your CoffeeScript to output to JavaScript, so that you can follow along.

To compile a directory of .coffee files to a parallel tree of .js files, we first write coffee followed by -o, which means output, followed by the directory where we want our JavaScripts to be stored. Then we add -c, which means compile, followed by the directory where our CoffeeScripts are stored.

coffee -o javascript/ -c coffees/

As you can see, the example.coffee compiles down to example.js. There is a little gotcha here that we should mention: if you reverse the order of the -c and -o options, it doesn't work. So you need the output first, then the compile option second with the CoffeeScript directory you want to compile.

But running this command every time you want to compile your CoffeeScript could get a little tedious, so, there's a -w option you can include after the coffee command. [this sets up a 'watcher' that will do the conversion automatically between the two folders]

coffee -w -o javascript/ -c coffees/

There's another gotcha here to be aware of: If you add a file to the folder where the CoffeeScripts are stored, and if the watcher is already running, it won't pick it up. You'll need to stop and start it again, and then the watcher will be aware of it. This may change in later versions.

You may want to compile all of your CoffeeScript files down into one JavaScript file so that a user's brower doesn't make multiple HTTP requests. To do this, add the -j or --join option followed by the JavaScript file name you want to compile all your CoffeeScript files into. You need to specify the CoffeeScript files you want to compile. You can specify multiple files, or use a wildcard operator.

coffee -j javascript/app.js -c coffees/*.coffee

As you can see a app.js file is created in the javascript folder.

The other helpful way to play around with the coffee command is to just type coffee with no options or arguments. This opens an interactive shell similar to irb in Ruby. So this can be a great tool to try things out in your console.

TextMate Bundle

There's also a TextMate bundle, created by CoffeeScript's inventor, Jeremy Ashkenas.

To install it, visit the GitHub repository, and copy and paste the commands into the terminal window.

mkdir -p ~/Library/Application\ Support/TextMate/Bundles
cd ~/Library/Application\ Support/TextMate/Bundles
git clone git://github.com/jashkenas/coffee-script-tmbundle CoffeeScript.tmbundle

We'll need to restart TextMate in order to load the bundle.

This bundle doesn't just have syntax highlighting, but also has two commands which you can run. First, it includes "Compile and Display JS", which compiles the code in your editor, or a selected portion in your code, and shows you the compiled JavaScript code. The second command is "Run", which compiles the code in your editor and evaluates the JavaScript and shows you the result of the execution.

To "Compile and Display JS", hit Command + B. To "Run", hit Command + R. Just remember B to build, and R to run.

Please note that these two tasks may not work out-of-the-box, since TextMate's PATH variable may not be set to include your terminal's PATH. You terminal path will include additional directories, so that you can run the packages installed with Homebrew.

To update TextMate with the correct PATH, first echo your $PATH variable in your terminal, and copy it. Then go to TextMate, Preferences, Advanced, and Shell Variables. Uncheck the PATH already there, and hit the add button. Then enter PATH for the Variable section, and paste in your real path into the Value section.

Now you should be all set up. So let's get into CoffeeScript itself.

Declaring Variables

To declare variables in CoffeeScript, you don't need any special var declarations. You simply type the variable name, an equals sign, and then the value.

hours_worked = 39
client_rate = 85

Strings

In CoffeeScript, strings are declared with quotes, as in most languages.

word = "Hello"

If you want to concatenate (or join) strings, you can list them one after another with a plus symbol in between, like this:

greeting = word + " World!"

Or, you can include the # symbol and encapsulate it in parentheses within the string.

greeting = "#{word} World!"
# 'Hello World!'

Note that this method of string interpolation only works when you use double quotes. If you use single-quotes, it resolves to the text as-is. In other words, single quote strings are literal strings.

greeting = '#{word} World!'
# '#{word} World!'

You'll likely recognize this behavior if you have a Ruby background.

Functions

Functions are declared by specifying the name of the function, followed by an equals sign, and then a function symbol, ->.

amount_billable = -> hours_worked * client_rate

As you see, we haven't called return at the end of the function. That's because every function returns the last line of code.

If you want to do a multi-lined function, all you need to do is add a return after the function symbol (->), and then add some white space before each line that you want to run in that function.

amount_billable = -> 
  hours_worked * client_rate

Let's add another line to see what that looks like. Let's add a tax_rate of 5%.

amount_billable = -> 
  tax_rate = 1.05
  hours_worked * client_rate * tax_rate

Now this is fairly static. We should probably setup some arguments, so that we can pass in different values for hours and rate. Just before the function symbol (->), we'll add parentheses with the argument names separated by commas.

amount_billable = (hours, rate) -> 
  tax_rate = 1.05
  hours * rate * tax_rate

Another bit of syntactic sugar that's built into method signatures is the option to add default values. So we can move our tax_rate = 1.05 into our method signature.

amount_billable = (hours, rate,  tax_rate = 1.05) -> 
  hours * rate * tax_rate

With that, we can bring our function code back to just one line.

amount_billable = (hours, rate,  tax_rate = 1.05) ->  worked * rate * tax_rate

Arrays

Arrays can be declared several different ways in CoffeeScript. We're all used to seeing array declarations with square brackets, and values separated by commas.

languages = ["JavaScript", "Ruby", "Python", "PHP"]

However, CoffeeScript has a few other helpful ways to write arrays. First, you can declare arrays over multiple lines like this:

languages = [
 "JavaScript", 
 "Ruby", 
 "Python", 
 "PHP"
]

But you have to remember your white space on each line.

You can also optionally remove the trailing comma from each line.

languages = [
 "JavaScript"
 "Ruby"
 "Python"
 "PHP"
]

You can also use a combination of these two declaration styles. Let's say we have a Sudoku sub-grid that we want to write in a readable format for the start of a game.

First we'll declare a name sub_grid, open the square brackets, and on each line we'll write the 3 values per line seperated by a comma, leaving the comma off after the last value in each line.

sub_grid = [
  5, 3, 0
  6, 0, 0
  0, 9, 8
]

As you can see, declaration of arrays is varied, and can be used to make code more readable in different situations.

Ranges

Ranges are declared by an integer, then two periods, then another number, all wrapped in square brackets.

months = [1..12]

This gets compiled down in to an array in JavaScript, since Ranges aren't a standard object type in Javascript.

You can also pass ranges into arrays, in order to get sub-sections of those arrays. Let's say we want to get the months from march_to_may. So, we want to start at index 2 and end at index 4. Remember, array indexes are zero-based.

months = [1..12]

march_to_may = months[2..4]

You can also replace values in arrays by a similar technique. Let's say we want to replace the month numbers from 3 to 5 with their name counterparts. To do this, you set the range months[2..4] to ["March", "April", "May"].

months[2..4] = ["March", "April", "May"]

The months array has now been changed to: [1, 2, 'March', 'April', 'May', 6, 7, 8, 9, 10, 11, 12]

A quick aside: Ranges in CoffeeScript can be in reverse order. For example if you wanted to count down from 15 to 0 you'd say countdown = [15..0].

Hashes

Hashes or JSON objects can be declared in the usual way, declaring the key/value pairs we're all familiar with.

secret_monkey_scientists = {
  voice: {
    name: "Josh Timonen", 
    age: 30
  }, 
  tech: {
    name:"Andrew Chalkley",
    age:28
  }
}

While this works fine in CoffeeScript, you can drop the commas and parentheses.

secret_monkey_scientists =
  voice:
    name: "Josh Timonen"
    age: 30
  tech:
    name:"Andrew Chalkley"
    age:28

As long as you indent with some white space, the structure gets nested as you'd expect.

Splat

A great addition to the tools already provided by CoffeeScript are splats. A splat is a convenient way to accept and pass in multiple values as arguments to methods.

OK, so let's say we want to allocate points for people who check in to a store in a particular hour.

Lets say the first person gets 5 points, the second gets 3, and every one else will get one point.

Let's create a function, allocatePoints.

allocatePoints = ->

Then, let's add some parameters. first for the first person, and second for the second person.

allocatePoints = (first, second) ->

Now what about the rest? Well, since we don't know how many people there will be, this is an ideal time to use a splat. To declare a splat, you give the name of the variable followed but three periods. Let's call ours rest followed by three periods (...).

allocatePoints = (first, second, rest...) ->

Now let's call a function we haven't declared yet, addPointsToUser. It'll take a user as the first parameter, and the number of points to be added to the user as the second parameter.

allocatePoints = (first, second, rest...) ->
  addPointsToUser first, 5
  addPointsToUser second, 3

Let's create our addPointsToUser function.

addPointsToUser = (user, points) ->

Within this function we're not going to do anything other than log the user and the points added.

addPointsToUser = (user, points) ->
  console.log "#{user} was assigned #{points} points"

OK so let's try this out.

Let's declare a users array users.

users = [
  "Andrew"
  "Josh"
  "Lauren"
  "Maureen"
  ]

Now let's pass in the array to the allocatePoints method.

allocatePoints users

When we hit command R to run, we get a result we're not expecting...

Andrew,Josh,Lauren,Maureen was assigned 5 points

undefined was assigned 3 points

That's because when you use splats in the declaration of your method, you must also use a splat, the three periods (...), after the variable passed in to that method. So in our case we need to do users...

allocatePoints users...

When we run again we get the right result showing the allocation of 5 points to Andrew and 3 points to Josh.

However we're missing the rest of the 1 point allocations. To do this, we can use a for loop. We'll write for user in rest, and then nested within this, we'll addPointstoUser user, adding 1 point.

allocatePoints = (first, second, rest...) ->
  addPointsToUser first, 5
  addPointsToUser second, 3
  for user in rest
    addPointsToUser user, 1

Now while it's nice to write code like this, CoffeeScript allows you two write loops in a more concise way, with comprehensions.

Comprehensions

Comprehensions work particularly well if you have a loop with just one line of code. In our case, the for loop can be written on one line, with the one line of code prepending the for statement.

allocatePoints = (first, second, rest...) ->
  addPointsToUser first, 5
  addPointsToUser second, 3
  addPointsToUser user, 1 for user in rest

Another neat trick is if you ever want to store the results of a particular operation into an array, all you need to do is assign a variable name to the loop.

Let's say we want to store the first ten multiples of 2 in an array called multiples. To do this, we'd first write multiples = followed by the for loop for num in [1..10], then the line of code you want to execute in each cycle, num * 2.

multiples = for num in [1..10]
                     num * 2

This can also be written on one line, but we'd need to add parentheses.

multiples = (num * 2 for num in [1..10])

General Syntax

So far we've covered the basics: the types of objects that can be created in CoffeeScript, how to declare them, iterate over them and how to write and call functions. But CoffeeScript offers more syntactic sugar in the general language.

For example you can write code that looks like it's written in English. For example you can write:

illuminate() if button is on

Which is the same as:

illuminate() unless button is not on

Obviously, different scenarios and other considerations will factor into your keyword choices. The second example is just to show you there's another way of writing it.

Here's a list of additional keywords and syntactic sugar that CoffeeScript brings to the table.

is === isnt !== not ! and && or || true, yes, on true false, no, off false @, this this of in in no equivalent

For examples of how to use these operators and aliases please see the CoffeeScript documentation.

Existential Operator

Another great addition that CoffeeScript brings is the Existential Operator, which is a question mark (?).

Let's say you want to call the function login() if the username hasn't been set yet. All you would do is type login() if not username with a question mark (?) at the end.

login() if not username?

The Existential Operator is also good for setting values if they haven't been set, just like this:

last_login ?= "unknown"

message = "Your last login was from : #{last_login}"

So if the last_login variable isn't set, the string is "unknown".

The third way you can use the Existential Operator is in a similar way to a ternary operator.

message = greeting ? "Hello World"

In this example the message would be set as whatever the greeting variable is or if greeting is undefined or not present "Hello World" would be the value of the message.

Classes

Writing classes in JavaScript hasn't been that straight forward. With CoffeeScript it's trivialised. To declare a class, all you need to is write the keyword class, followed by the name of your class.

class Animal

Methods for classes are written with the name of the method followed by a colon. Of course, you need to include some white space before the method name. You can include method arguments in parentheses, then followed by the function arrow (->).

There is one method you can define that is used for constructing new objects. This method is called constructor.

class Animal
  constructor: ->

Instance Variables

Let's pass in the animal's name into the constructor. We can assign the name to an instance variable. As you can see, an instance variable is just like an instance variable in Ruby, with an at-symbol (@) in front.

class Animal
  constructor: (name) ->
    @name = name

We can access this variable at a later point using dot notation.

class Animal
 constructor: (name) ->
    @name = name

dog = new Animal "Bingo"

console.log dog.name

There's a short-hand way that you can write this pattern of a method and the setting of an instance variable; all you need to do is move the instance variable into the method signature.

So our constructor now looks like this:

class Animal
 constructor: (@name) ->

Inheritance

When introducing objects into any code, it won't be long before you're making sub-classes.

Let's create a noise method called makeNoise, where we display the name of the animal and the noise it makes.

class Animal
 constructor: (@name) ->
 makeNoise: (noise) ->
   console.log "#{@name} makes the noise #{noise}"

Let's create two subclasses of Animal; Dog and Cat. To write a subclass, use the keyword class followed by the name of the subclass, followed by the keyword extends and the superclass you want it to inherit from.

class Dog extends Animal

We can then define our subclass-specific makeNoise methods.

class Dog extends Animal
  makeNoise: ->

class Cat extends Animal
  makeNoise: ->

Within these two methods, we can call super and pass in the parameters required for the superclass' method signature.

class Dog extends Animal
  makeNoise: ->
    super "bark"

class Cat extends Animal
  makeNoise: ->
    super "nyan"

Now let's instantiate a Dog and a Cat and make them make a noise.

dog = new Dog "Bingo"
cat = new Cat "Pop Tart Cat"

dog.makeNoise()
cat.makeNoise()

And as you can see the right animals make the right noises.

Bingo makes the noise bark 
Pop Tart Cat makes the noise nyan

Conclusion

We've only scratched the surface, and we really encourage you to check out the CoffeeScript documentation to see the full extent of what CoffeeScript has to offer.

Thanks for watching! Subscribe to our RSS feed, follow us on Twitter, and please leave any questions, comments or suggestions for new screencasts in the comments below. If you like our videos, and think your friends, followers or colleagues would benefit from seeing them, please feel free share via any of the links below the video. We really appreciate your support.

See you next time!

Help support Screencasts.org by purchasing the Screencasts iPhone and iPad apps, available through the App Store and iTunes. Blip.tv recently made some changes to their API, and we had to update some code in the apps for video playback. We apologize for any inconvenience, and the apps are updated now in the App Store. You can also donate directly via PayPal in the side bar. Thanks in advance for helping us share this content.

← Latest Episodes

blog comments powered by Disqus