CoffeeScript Programming with jQuery, Rails, and Node.js

4 (2 reviews total)
By Michael Erasmus
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Why CoffeeScript?

About this book

CoffeeScript is a young but popular language that makes web programming fun and more productive. It compiles to JavaScript and unleashes its powerful features while not straying too far from the language. It’s become one of the most popular languages on Github and is being used for both browser and server side programming.

"CoffeeScript programming with jQuery, Rails, and Node.js" will not only teach you the CoffeeScript language but also show you how it’s being used by professional programmers with the latest web technologies.

This book will teach you the basics of the language, focusing particularly on how it improves on JavaScript. It then focuses on building real life projects in CoffeeScript using jQuery, Rails, and Node.js.

We look at CoffeeScript as a language that takes the power of JavaScript and presents it in an elegant and concise syntax. We will then see how we can use its power to write beautiful and short programs for various environments and how it complements the latest and greatest web frameworks.

CoffeeScript programming with jQuery, Rails, and Node.js is all you need to become well versed with this great language and set you on your way to using it to write web applications.

Publication date:
December 2012
Publisher
Packt
Pages
140
ISBN
9781849519588

 

Chapter 1. Why CoffeeScript?

CoffeeScript compiles to JavaScript and follows its idioms closely. It's quite possible to rewrite any CoffeeScript code in Javascript and it won't look drastically different. So why would you want to use CoffeeScript?

As an experienced JavaScript programmer, you might think that learning a completely new language is simply not worth the time and effort.

But ultimately, code is for programmers. The compiler doesn't care how the code looks or how clear its meaning is; either it will run or it won't. We aim to write expressive code as programmers so that we can read, reference, understand, modify, and rewrite it.

If the code is too complex or filled with needless ceremony, it will be harder to understand and maintain. CoffeeScript gives us an advantage to clarify our ideas and write more readable code.

It's a misconception to think that CoffeeScript is very different from JavaScript. There might be some drastic syntax differences here and there, but in essence, CoffeeScript was designed to polish the rough edges of JavaScript to reveal the beautiful language hidden beneath. It steers programmers towards JavaScript's so-called "good parts" and holds strong opinions of what constitutes good JavaScript.

One of the mantras of the CoffeeScript community is: "It's just JavaScript", and I have also found that the best way to truly comprehend the language is to look at how it generates its output, which is actually quite readable and understandable code.

Throughout this chapter, we'll highlight some of the differences between the two languages, often focusing on the things in JavaScript that CoffeeScript tries to improve.

In this way, I would not only like to give you an overview of the major features of the language, but also prepare you to be able to debug your CoffeeScript from its generated code once you start using it more often, as well as being able to convert existing JavaScript.

Let's start with some of the things CoffeeScript fixes in JavaScript.

 

CoffeeScript syntax


One of the great things about CoffeeScript is that you tend to write much shorter and more succinct programs than you normally would in JavaScript. Some of this is because of the powerful features added to the language, but it also makes a few tweaks to the general syntax of JavaScript to transform it to something quite elegant. It does away with all the semicolons, braces, and other cruft that usually contributes to a lot of the "line noise" in JavaScript.

To illustrate this, let's look at an example. On the left-hand side of the following table is CoffeeScript; on the right-hand side is the generated JavaScript:

CoffeeScript

JavaScript

fibonacci = (n) ->
 return 0 if n == 0
 return 1 if n == 1
 (fibonacci n-1) + (fibonacci n-2)

alert fibonacci 10
var fibonacci;

fibonacci = function(n) {
  if (n === 0) {
    return 0;
  }
  if (n === 1) {
    return 1;
  }
  return (fibonacci(n - 1)) + (fibonacci(n - 2));
}; 

alert(fibonacci(10));

To run the code examples in this chapter, you can use the great Try CoffeeScript online tool, at http://coffeescript.org. It allows you to type in CoffeeScript code, which will then display the equivalent JavaScript in a side pane. You can also run the code right from the browser (by clicking the Run button in the upper-left corner). If you prefer to get CoffeeScript running on your computer to run the samples first, skip to the next chapter and then come back once you have CoffeeScript installed. This tool is shown in the following screenshot:

At first, the two languages might appear to be quite drastically different, but hopefully as we go through the differences, you'll see that it's all still JavaScript with some small tweaks and a lot of nice syntactical sugar.

Semicolons and braces

As you might have noticed, CoffeeScript does away with all the trailing semicolons at the end of a line. You can still use a semicolon if you want to put two expressions on a single line. It also does away with enclosing braces (also known as curly brackets) for code blocks such as if statements, switch, and the try..catch block.

Whitespace

You might be wondering how the parser figures out where your code blocks start and end. The CoffeeScript compiler does this by using syntactical whitespace. This means that indentation is used for delimited code blocks instead of braces.

This is perhaps one of the most controversial features of the language. If you think about it, in almost all languages, programmers tend to already use indentation of code blocks to improve readability, so why not make it part of the syntax? This is not a new concept, and was mostly borrowed from Python. If you have any experience with significant whitespace language, you will not have any trouble with CoffeeScript indentation.

If you don't, it might take some getting used to, but it makes for code that is wonderfully readable and easy to scan, while shaving off quite a few keystrokes. I'm willing to bet that if you do take the time to get over some initial reservations you might have, you might just grow to love block indentation.

Note

Blocks can be indented with tabs or spaces, but be careful about being consistent using one or the other, or CoffeeScript will not be able to parse your code correctly.

Parenthesis

You'll see that the clause of the if statement does not need be enclosed within parentheses. The same goes for the alert function; you'll see that the single string parameter follows the function call without parentheses as well. In CoffeeScript, parentheses are optional in function calls with parameters, clauses for if..else statements, as well as while loops.

Although functions with arguments do not need parentheses, it is still a good idea to use them in cases where ambiguity might exist. The CoffeeScript community has come up with a nice idiom: wrapping the whole function call in parenthesis. The use of the alert function in CoffeeScript is shown in the following table:

CoffeeScript

JavaScript

alert square 2 * 2.5 + 1

alert (square 2 * 2.5) + 1
alert(square(2 * 2.5 + 1));

alert((square(2 * 2.5)) + 1);

Functions are first class objects in JavaScript. This means that when you refer to a function without parentheses, it will return the function itself, as a value. Thus, in CoffeeScript you still need to add parentheses when calling a function with no arguments.

By making these few tweaks to the syntax of JavaScript, CoffeeScript arguably already improves the readability and succinctness of your code by a big factor, and also saves you quite a lot of keystrokes.

But it has a few other tricks up its sleeve. Most programmers who have written a fair amount of JavaScript would probably agree that one of the phrases that gets typed the most frequently would have to be the function definition function(){}. Functions are really at the heart of JavaScript, yet not without its many warts.

 

CoffeeScript has great function syntax


The fact that you can treat functions as first class objects as well as being able to create anonymous functions is one of JavaScript's most powerful features. However, the syntax can be very awkward and make the code hard to read (especially if you start nesting functions). But CoffeeScript has a fix for this. Have a look at the following snippets:

CoffeeScript

JavaScript

-> alert 'hi there!'
square = (n) -> n * n
var square;
(function() {
  return alert('hi there!');
});
square = function(n) {
  return n * n;
};

Here, we are creating two anonymous functions, the first just displays a dialog and the second will return the square of its argument. You've probably noticed the funny -> symbol and might have figured out what it does. Yep, that is how you define a function in CoffeeScript. I have come across a couple of different names for the symbol but the most accepted term seems to be a thin arrow or just an arrow. This is as opposed to the fat arrow, which we'll discuss later.

Notice that the first function definition has no arguments and thus we can drop the parenthesis. The second function does have a single argument, which is enclosed in parenthesis, which goes in front of the -> symbol. With what we now know, we can formulate a few simple substitution rules to convert JavaScript function declarations to CoffeeScript. They are as follows:

  • Replace the function keyword with ->

  • If the function has no arguments, drop the parenthesis

  • If it has arguments, move the whole argument list with parenthesis in front of the -> symbol

  • Make sure that the function body is properly indented and then drop the enclosing braces

Return isn't required

You might have noted that in both the functions, we left out the return keyword. By default, CoffeeScript will return the last expression in your function. It will try to do this in all the paths of execution. CoffeeScript will try turning any statement (fragment of code that returns nothing) into an expression that returns a value. CoffeeScript programmers will often refer to this feature of the language by saying that everything is an expression.

This means you don't need to type return anymore, but keep in mind that this can, in many cases, alter your code subtly, because of the fact that you will always return something. If you need to return a value from a function before the last statement, you can still use return.

Function arguments

Function arguments can also take an optional default value. In the following code snippet you'll see that the optional value specified is assigned in the body of the generated Javascript:

CoffeeScript

JavaScript

square = (n=1) ->
  alert(n * n)
var square;

square = function(n) {
  if (n == null) {
    n = 1;
  }
  return alert(n * n);
};

In JavaScript, each function has an array-like structure called arguments with an indexed property for each argument that was passed to the function. You can use arguments to pass in a variable number of parameters to a function. Each parameter will be an element in arguments and thus you don't have to refer to parameters by name.

Although the arguments object acts somewhat like an array, it is in not in fact a "real" array and lacks most of the standard array methods. Often, you'll find that arguments doesn't provide the functionality needed to inspect and manipulate its elements like they are used with an array.

This has forced many programmers to use a hack by making Array.prototype.slice copy the argument object elements, or to use the jQuery.makeArray method to create a standard array, which can then be used like normal.

CoffeeScript borrows this pattern of creating an array from arguments that are represented by splats , denoted with three dots (...). These are shown in the following code snippet:

CoffeeScript:

gpaScoreAverage = (scores...) ->
   total = scores.reduce (a, b) -> a + b
   total / scores.length

alert gpaScoreAverage(65,78,81)
scores = [78, 75, 79]
alert gpaScoreAverage(scores...)

JavaScript:

var gpaScoreAverage, scores,
  __slice = [].slice;

gpaScoreAverage = function() {
  var scores, total;
  scores = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  total = scores.reduce(function(a, b) {
    return a + b;
  });
  return total / scores.length;
};

alert(gpaScoreAverage(65, 78, 81));
scores = [78, 75, 79];
alert(gpaScoreAverage.apply(null, scores));

Notice that in the function definition, the parameter is followed by .... This tells CoffeeScript to allow for variable arguments. The function can then be invoked using either a list of parameters or an array followed by ....

Where did the var keyword go?

In JavaScript, you create local variables by prefixing their declarations with a var keyword. If you omit it, the variable will be created in the global scope.

You'll see throughout these examples that that we didn't need to use the var keyword, and that CoffeeScript created the actual variable declarations at the top of the function in the generated JavaScript.

If you're an experienced JavaScripter, you might be wondering how you would then go about creating global variables. The simple answer is you can't.

Many people (probably including the authors of CoffeeScript) would argue that this is a good thing, because in most cases global variables should be avoided. Don't fret though, as there are ways to create top-level objects that we'll get to in a moment. But this does lead us neatly onto another benefit of CoffeeScript.

 

CoffeeScript handles scope better


Take a look at the following snippet of JavaScript. Notice that a variable called salutation gets defined in two places, inside the function, as well as after the function gets called the first time:

JavaScript

var greet = function(){ 
    if(typeof salutation === 'undefined') 
        salutation = 'Hi!'; 
    console.log(salutation); 
}
greet();
salutation = "Bye!";
greet();

In JavaScript, when you omit the var keyword while declaring a variable, it immediately becomes a global variable. Global variables are available in all scopes, and thus can be overwritten from anywhere, which often ends up as being a mess.

In the previous example, the greet function first checks if the salutation variable is defined (by checking if typeof equals undefined, a common workaround to see if a variable is defined in JavaScript). If it has not been defined previously, it creates it without a var keyword. This will immediately promote the variable to the global scope. We can see the consequences of this in the rest of the snippet.

The first time the greet function is called, the string Hi! will be logged. After the salutation has been changed and the function is called again, the console will instead log Bye!. Because the variable was leaked to be a global variable, its value was overwritten outside of the function scope.

This odd "feature" of the language has been the cause of many a headache for some weary programmer who forgot to include a var keyword somewhere. Even if you mean to declare a global variable, it is generally considered to be a bad design choice, which is why CoffeeScript disallows it.

CoffeeScript will always add the var keyword to any variable declaration to make sure that it doesn't inadvertently end up as a global declaration. In fact, you should never type var yourself, and the compiler will complain if you do.

Top level var keywords

When you declare a var normally at the top level of your script in JavaScript, it will still be available globally. This can also cause havoc when you include a bunch of different JavaScript files, since you might overwrite variables declared in earlier scripts.

In JavaScript and subsequently CoffeeScript, functions act as closures, meaning that they create their own variable scope as well as having their enclosing scope variables available to them.

Throughout the years, a common pattern started to emerge where library authors wrap their entire script in an anonymous closure function that they assign to a single variable.

The CoffeeScript compiler does something similar, and will wrap scripts in an anonymous function to avoid leaking its scope. In the following sample, the JavaScript is the output of running the CoffeeScript compiler:

CoffeeScript

JavaScript

greet = -> salutation = 'Hi!'
(var greet;
greet = function() {
  var salutation;
  return salutation = 'Hi!';
}).call(this);

Here you can see how CoffeeScript has wrapped the function definition in its own scope.

There are, however, certain cases where you would want a variable to be available throughout your application. Usually attaching a property to an existing global object can do this. When you're in the browser, you can just create a property on the global window object.

In browser-side JavaScript, the window object represents an open window. It's globally available to all other objects and thus can be used as a global namespace or container for other objects.

While we are on the subject of objects, let's talk about another part of JavaScript that CoffeeScript makes much better: defining and using objects.

 

CoffeeScript has better object syntax


The JavaScript language has a wonderful and unique object model, but the syntax and semantics for creating objects and inheriting from them has always been a bit cumbersome and widely misunderstood.

CoffeeScript cleans this up in a simple and elegant syntax that does not stray too far from idiomatic JavaScript. The following code demonstrates how CoffeeScript compiles its class syntax into JavaScript:

CoffeeScript:

class Vehicle
  constructor: ->   
  drive: (km) -> 
    alert "Drove #{km} kilometres"

bus = new Vehicle()
bus.drive 5

JavaScript:

var Vehicle, bus;
Vehicle = (function() {
  function Vehicle() {}
  Vehicle.prototype.drive = function(km) {
    return alert("Drove " + km + " kilometres");
  };
  return Vehicle;
})();
bus = new Vehicle();
bus.drive(5);

In CoffeeScript, you use the class keyword to define object structures. Under the hood, this creates a function object with function methods added to its prototype. The constructor: operator will create a constructor function that will be called when your object gets initialized with the new keyword.

All the other function methods are declared using the methodName: () -> syntax. These are created on the prototype of the object.

Note

Did you notice the #{km} in our alert string? This is the string interpolation syntax, which was borrowed from Ruby. We'll talk about this later in the chapter.

Inheritance

What about object inheritance? Although it's possible, normally this is such a pain in JavaScript that most programmers don't even bother, or use a third-party library with non-standard semantics.

In this example you can see how CoffeeScript makes object inheritance elegant:

CoffeeScript:

class Car extends Vehicle
  constructor: -> 
    @odometer = 0
  drive: (km) ->
    @odometer += km
    super km
car = new Car
car.drive 5
car.drive 8

alert "Odometer is at #{car.odometer}"

JavaScript:

Car = (function(_super) {
  __extends(Car, _super);
  function Car() {
    this.odometer = 0;
  }
  Car.prototype.drive = function(km) {
    this.odometer += km;
    return Car.__super__.drive.call(this, km);
  };
  return Car;
})(Vehicle);

car = new Car;
car.drive(5);
car.drive(8);
alert("Odometer is at " + car.odometer);

This example does not contain all the JavaScript code that will be generated by the compiler, but has enough to highlight the interesting parts. The extends operator is used to set up the inheritance chain between two objects and their constructors. Notice how much simpler the call to the parent class becomes with super.

As you can see, @odometer was translated to this.odometer. The @ symbol is just a shortcut for this. We'll talk about it further on in this chapter.

Overwhelmed?

The class syntax is, in my opinion, where you'll find the greatest difference between CoffeeScript and its compiled JavaScript. However, most of the time it just works and once you understand it you'll rarely have to worry about the details.

Extending prototypes

If you're an experienced JavaScript programmer who still likes to do all of this yourself, you don't need to use class. CoffeeScript still provides the helpful shortcut to get at prototypes through the :: symbol, which will be replaced by .prototype in the generated JavaScript, as shown in the following code snippet:

CoffeeScript

JavaScript

Vehicle::stop=->  alert'Stopped'
Vehicle.prototype.stop(function() {
  return alert('Stopped');
});
 

A few other things CoffeeScript fixes


JavaScript has lots of other small annoyances that CoffeeScript makes nicer. Let's have a look at some of these.

Reserved words and object syntax

Often in JavaScript, you will need to make use of a reserved word, or a keyword that is used by JavaScript. This often happens with keys for literal objects as data in JavaScript, like class or for, which you then need to enclose in quotes. CoffeeScript will automatically quote reserved words for you, and generally you don't even need to worry about it.

CoffeeScript

JavaScript

tag = 
  type: 'label' 
  name: 'nameLabel'
  for: 'name'
  class: 'label'
var tag;

tag = {
  type: 'label',
  name: 'nameLabel',
  "for": 'name',
  "class": 'label'
};

Notice that we don't need the braces to create object literals and can use indentation here as well. While using this style, as long as there is only one property per line, we can drop the trailing commas too.

We can also write array literals in this way:

CoffeeScript

JavaScript

dwarfs = [
  "Sneezy"
  "Sleepy"
  "Dopey"
  "Doc"
  "Happy"
  "Bashful"
  "Grumpy"
]
var dwarfs;

dwarfs = ["Sneezy", "Sleepy", "Dopey", "Doc", "Happy", "Bashful", "Grumpy"];

These features combined make writing JSON a breeze. Compare the following samples to see the difference:

CoffeeScript:

"firstName": "John"
"lastName": "Smith"
"age": 25
"address": 
  "streetAddress": "21 2nd Street"
  "city": "New York"
  "state": "NY"
  "postalCode": "10021"
"phoneNumber": [
  {"type": "home", "number": "212 555-1234"}
  {"type": "fax", "number": "646 555-4567"}
]

JavaScript:

({
  "firstName": "John",
  "lastName": "Smith",
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
  },
  "phoneNumber": [
    {
      "type": "home",
      "number": "212 555-1234"
    }, {
      "type": "fax",
      "number": "646 555-4567"
    }
  ]
});

String concatenation

For a language that deals with a lot of strings, JavaScript has always been pretty bad at building strings up from parts. Variables and expression values are often meant to be inserted inside a string somewhere, and this is usually done by concatenation using the + operator. If you've ever tried concatenating a couple of variables in a string, you'll know this soon becomes burdensome and hard to read.

CoffeeScript has a built-in string interpolation syntax, which is similar to many other scripting languages, but was specifically borrowed from Ruby. This is shown in the following code snippet:

CoffeeScript

JavaScript

greet = (name, time) -> 
  "Good #{time} #{name}!"

alert (greet 'Pete', 'morning')
var greet;

greet = function(name, time) {
  return "Good " + time + " " + name + "!";
};

alert(greet('Pete', 'morning'));

You can write any expression within #{} and its string value will be concatenated. Note that you can only use string interpolation in double-quoted strings, "". Single-quoted strings are literal and will be represented exactly how they are.

Equality

The equality operator == (and its inverse !=) in JavaScript is fraught with dangers, and a lot of times doesn't do what you would expect. This is because it will first try to coerce objects of a different type to be the same before comparing them.

It's also not transitive, meaning it might return different values of true or false depending on if a type is on the left or right of the operator. Please refer to the following code snippet:

'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

Because of its inconsistent and strange behavior, respected members in the JavaScript community advise avoiding it altogether and to rather use the identity operator, === in its place. This operator will always return false if two objects are of a different type, which is consistent to how == works in many other languages.

CoffeeScript will always convert == to === and != to !===, as shown in the following implementation:

CoffeeScript

JavaScript

'' == '0'
0 == ''  
0 == '0' 
false == 'false'
false == '0'    
false == undefined
false == null     
null == undefined 
'' === '0';
0 === '';
0 === '0';
false === 'false';
false === '0';
false === void 0;
false === null;
null === void 0;

The existential operator

When you're trying to check if a variable exists and has a value (is not null or undefined) in JavaScript, you need to use this quirky idiom:

typeof a !== "undefined" && a !== null 

CoffeeScript has a nice shortcut for this, the existential operator ?, which will return false unless a variable is undefined or null.

CoffeeScript

JavaScript

broccoli = true;
if carrots? && broccoli?
  alert 'this is healthy'
var broccoli;

broccoli = true;

if ((typeof carrots !== "undefined" && carrots !== null) && (broccoli != null)) {
  alert('this is healthy');
}

In this example, since the compiler already knows that broccoli is defined, the ? operator will only check if it has a null value, while it will check if carrots is undefined as well as null.

The existential operator has a method call variant: ?. or just the "soak", which will allow you to swallow the method calls on null objects in a method chain, as shown here:

CoffeeScript

JavaScript

street = person?.getAddress()?.street
var street, _ref;

street = typeof person !== "undefined" && person !== null ? (_ref = person.getAddress()) != null ? _ref.street : void 0 : void 0;

If all of the values in the chain exist, you should get the expected result. If any of them should be null or undefined, you will get an undefined value, instead of TypeError being thrown.

Although this is a powerful technique, it can also be easily abused and make the code hard to reason with. If you have long method chains it may become hard to know just exactly where the null or undefined value came from.

The Law of Demeter , a well-known object orientation design principle, can be used to minimize this kind of complexity and improve decoupling in your code. It can be summarized as follows:

  • Your method can call other methods in its class directly

  • Your method can call methods on its own fields directly (but not on the fields' fields)

  • When your method takes parameters, your method can call methods on those parameters directly

  • When your method creates local objects, that method can call methods on the local objects

Note

Although, this is not a "strict law" in the sense that it should never be broken, it is more analogous to the law of nature, such that the code that tends to follow it also tends to be much simpler and more loosely coupled.

Now that we have spent some time going over some of the inadequacies and annoyances of JavaScript that CoffeeScript fixes, let's dwell on some of the other powerful features that CoffeeScript adds; some borrowed from other scripting languages and some that are unique to the language.

 

List comprehensions


In CoffeeScript, looping through collections works quite differently from JavaScript's imperative approach. CoffeeScript takes ideas from functional programming languages and uses list comprehensions to transform lists instead of looping through elements iteratively.

The while loop

The while loop is still present and works more or less the same, except that it can be used as an expression, meaning it will return an array of values:

CoffeeScript:

multiplesOf = (n, times) -> 
  times++
  (n * times while times -= 1 > 0).reverse()

alert (multiplesOf 5, 10)

JavaScript:

var multiplesOf;

multiplesOf = function(n, times) {
  times++;
  return ((function() {
    var _results;
    _results = [];
    while (times -= 1 > 0) {
      _results.push(n * times);
    }
    return _results;
  })()).reverse();
};

alert(multiplesOf(5, 10));

Notice that in the previous code, the while body goes in front of the condition. This is a common idiom in CoffeeScript if the body is of only one line. You can do the same thing with if statements and list comprehensions.

We can improve the readability of the previous code slightly by using the until keyword, which is basically the negation of while, as shown here:

CoffeeScript:

multiplesOf = (n, times) -> 
  times++
  (n * times until --times == 0).reverse()

alert (multiplesOf 5, 10)

JavaScript:

var multiplesOf;

multiplesOf = function(n, times) {
  times++;
  return ((function() {
    var _results;
    _results = [];
    while (--times !== 0) {
      _results.push(n * times);
    }
    return _results;
  })()).reverse();
};

alert(multiplesOf(5, 10));

The for statement doesn't work like it does in JavaScript. CoffeeScript replaces it with list comprehensions, which were mostly borrowed from the Python language and also very similar to constructs that you'll find in functional languages such as Haskell. Comprehensions provide a more declarative way of filtering, transforming, and aggregating collections or performing an action for each element. The best way to illustrate them would be through some examples:

CoffeeScript:

flavors = ['chocolate', 'strawberry', 'vanilla']
alert flavor for flavor in flavors

favorites = ("#{flavor}!" for flavor in flavors when flavor != 'vanilla')

JavaScript:

var favorites, flavor, flavors, _i, _len;

flavors = ['chocolate', 'strawberry', 'vanilla'];

for (_i = 0, _len = flavors.length; _i < _len; _i++) {
  flavor = flavors[_i];
  alert(flavor);
}

favorites = (function() {
  var _j, _len1, _results;
  _results = [];
  for (_j = 0, _len1 = flavors.length; _j < _len1; _j++) {
    flavor = flavors[_j];
    if (flavor !== 'vanilla') {
      _results.push("" + flavor + "!");
    }
  }
  return _results;
})();

Although they are quite simple, comprehensions have a very condensed form and do a lot in very little code. Let's break it down to its separate parts:

[action or mapping] for [selector] in [collection] when [condition] by [step]

Comprehensions are best read from right to left, starting from the in collection. The selector name is a temporary name that is given to each element as we iterate through the collection. The clause in front of the for keyword describes what you want to do with the selector name, by either calling a method with it as an argument, selecting a property or method on it, or assigning a value.

The when and by guard clauses are optional. They describe how the iteration should be filtered (elements will only be returned when their subsequent when condition is true), or which parts of the collection to select using by followed by a number. For example, by 2 will return every evenly numbered element.

We can rewrite our multiplesOf function by using by and when:

CoffeeScript:

multiplesOf = (n, times) -> 
  multiples = (m for m in [0..n*times] by n)
  multiples.shift()
  multiples

alert (multiplesOf 5, 10)

JavaScript:

var multiplesOf;

multiplesOf = function(n, times) {
  var m, multiples;
  multiples = (function() {
    var _i, _ref, _results;
    _results = [];
    for (m = _i = 0, _ref = n * times; 0 <= _ref ? _i <= _ref : _i >= _ref; m = _i += n) {
      _results.push(m);
    }
    return _results;
  })();
  multiples.shift();
  return multiples;
};

alert(multiplesOf(5, 10));

The [0..n*times] syntax is CoffeeScripts's range syntax, which was borrowed from Ruby. It will create an array with all the elements between the first and last number. When the range has two dots it will be inclusive, meaning the range will contain the specified start and end element. If it has three dots (), it will only contain the numbers in between.

List comprehensions were one of the biggest new concepts to grasp when I started learning CoffeeScript. They are an extremely powerful feature, but it does take some time to get used to and think in comprehensions. Whenever you feel tempted to write a looping construct using the lower level while, consider using a comprehension instead. They provide just about everything you could possibly need when working with collections, and they are extremely fast compared to built-in ECMAScript array methods, such as .map() and .select().

You can use comprehensions to loop through key-value pairs in an object, using the of keyword, as shown in the following code:

CoffeeScript:

ages = 
  john: 25
  peter: 26
  joan: 23

alert "#{name} is #{age} years old" for name, age of ages

JavaScript:

var age, ages, name;

ages = {
  john: 25,
  peter: 26,
  joan: 23
};

for (name in ages) {
  age = ages[name];
  alert("" + name + " is " + age + " years old");
}
 

Conditional clauses and logical aliases


CoffeeScript introduces some very nice logic and conditional features, some also borrowed from other scripting languages. The unless keyword is the inverse of the if keyword; if and unless can take the postfix form, meaning statements can go at the end of the line.

CoffeeScript also provides plain English aliases for some of the logical operators. They are as follows:

  • is for ==

  • isnt for !=

  • not for !

  • and for &&

  • or for ||

  • true can also be yes, or on

  • false can be no or off

Putting all this together, let's look at some code to demonstrate it:

CoffeeScript:

car.switchOff() if car.ignition is on
service(car) unless car.lastService() > 15000
wash(car) if car.isDirty()
chargeFee(car.owner) if car.make isnt "Toyota"

JavaScript:

if (car.ignition === true) {
  car.switchOff();
}

if (!(car.lastService() > 15000)) {
  service(car);
}

if (car.isDirty()) {
  wash(car);
}

if (car.make !== "Toyota") {
  chargeFee(car.owner);
}
 

Array slicing and splicing


CoffeeScript allows you to easily extract parts of an array using the .. and ... notation. [n..m] will select all the elements including n and m, whereas [n…m] will select only the elements between n and m.

Both [..] and […] will select the whole array. These are used in the following code:

CoffeeScript

JavaScript

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

alert numbers[0..3]

alert numbers[4...7]

alert numbers[7..]

alert numbers[..]
var numbers;

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

alert(numbers.slice(0, 4));

alert(numbers.slice(4, 7));

alert(numbers.slice(7));

alert(numbers.slice(0));

CoffeeScript sure loves its ellipses. They are used by splats, ranges, and array slices. Here are some quick tips on how to identify them: If the is next to the last argument in a function definition or a function call, it's a splat. If it's enclosed in square brackets that are not indexing an array, it's a range. If it is indexing an array, it's a slice.

 

Destructuring or pattern matching


Destructuring is a powerful concept that you'll find in many functional programming languages. In essence, it allows you to pull single values from complex objects. It can simply allow you to assign multiple values at once, or deal with functions that return multiple values; as shown here:

CoffeeScript:

getLocation = ->
  [
   'Chigaco' 
   'Illinois' 
   'USA'
  ]

[city, state, country] = getLocation()

JavaScript:

var city, country, getLocation, state, _ref;

getLocation = function() {
  return ['Chigaco', 'Illinois', 'USA'];
};

_ref = getLocation(), city = _ref[0], state = _ref[1], country = _ref[2];

When you run this, you get three variables, city, state, and country with values that were assigned from the corresponding element in the array returned by the getLocation function.

You can use destructuring to pull out values from objects and hashes as well. There are no limits to how deeply data in the object can be nested. Here is an example of that:

CoffeeScript:

getAddress = ->
   address:
     country: 'USA'
     state: 'Illinois'
     city: 'Chicago'
     street: 'Rush Street'
     

{address: {street: myStreet}} = getAddress()
alert myStreet

JavaScript:

var getAddress, myStreet;

getAddress = function() {
  return {
    address: {
      country: 'USA',
      state: 'Illinois',
      city: 'Chicago',
      street: 'Rush Street'
    }
  };
};

myStreet = getAddress().address.street;

alert(myStreet);

In this example, the {address: {street: ---}} part describes your pattern, basically where to find the information you need. When we put the myStreet variable inside our pattern, we tell CoffeeScript to assign the value in that place to myStreet. While we can use nested objects, we can also mix and match destructuring objects and arrays, as shown in the following code:

CoffeeScript:

getAddress = ->
   address:
     country: 'USA'
     addressLines: [
       '1 Rush Street'
       'Chicago'
       'Illinois'
     ]

{address: 
  {addressLines: 
    [street, city, state]
  }
} = getAddress()
alert street

JavaScript:

var city, getAddress, state, street, _ref;

getAddress = function() {
  return {
    address: {
      country: 'USA',
      addressLines: ['1 Rush Street', 'Chicago', 'Illinois']
    }
  };
};

_ref = getAddress().address.addressLines, street = _ref[0], city = _ref[1], state = _ref[2];

alert(street);

Here, in the previous code, we are pulling elements from the array value that we get from addressLines and give them names.

 

=> and @


In JavaScript, the value of this refers to the owner of the currently executing function, or the object that the function is a method of. Unlike in other object-oriented languages, JavaScript also has the notion that functions are not tightly bound to objects, meaning that the value of this can be changed at will (or accidently). This is a very powerful feature of the language but can also lead to confusion if used incorrectly.

In CoffeeScript, the @ symbol is a shortcut for this. Whenever the compiler sees something like @foo, it will replace it with this.foo.

Although it's still possible to use this in CoffeeScript, it's generally frowned upon and more idiomatic to use @ instead.

In any JavaScript function, the value of this is the object that the function is attached to. However, when you pass functions to other functions or reattach a function to another object, the value of this will change. Sometimes this is what you want, but often you would like to keep the original value of this.

For this purpose, CoffeeScript provides the =>, or fat arrow, which will define a function but at the same time capture the value of this, so that the function can be safely called in any context. This is especially useful when using callbacks, for instance in a jQuery event handler.

The following example will illustrate the idea:

CoffeeScript:

class Birthday
  prepare: (action) ->
    @action = action

  celebrate: () ->
   @action()

class Person
  constructor: (name) ->
    @name = name
    @birthday = new Birthday()
    @birthday.prepare () => "It's #{@name}'s birthday!"

michael = new Person "Michael"
alert michael.birthday.celebrate() 

JavaScript:

var Birthday, Person, michael;

Birthday = (function() {

  function Birthday() {}

  Birthday.prototype.prepare = function(action) {
    return this.action = action;
  };

  Birthday.prototype.celebrate = function() {
    return this.action();
  };

  return Birthday;

})();

Person = (function() {

  function Person(name) {
    var _this = this;
    this.name = name;
    this.birthday = new Birthday();
    this.birthday.prepare(function() {
      return "It's " + _this.name + "'s birthday!";
    });
  }

  return Person;

})();

michael = new Person("Michael");

alert(michael.birthday.celebrate());

Notice that the prepare function on the birthday class takes an action function as an argument, to be called when the birthday occurs. Because we're passing this function using the fat arrow, it will have its scope fixed to the Person object. This means we can still refer to the @name instance variable even though it doesn't exist on the Birthday object that runs the function.

 

Switch statements


In CoffeeScript, switch statements take a different form, and look a lot less like JavaScript's Java-inspired syntax, and a lot more like Ruby's case statement. You don't need to call break to avoid falling through to the next case condition.

They have the following form:

switch condition 
  when … then …
   ….
else …

Here, else is the default case.

Like everything else in CoffeeScript, they are expressions, and this can be assigned to a value.

Let's look at an example:

CoffeeScript:

languages = switch country
  when 'france' then 'french'
  when 'england', 'usa' then 'english'
  when 'belgium' then ['french', 'dutch']
  else 'swahili'

JavaScript:

var languages;

languages = (function() {
  switch (country) {
    case 'france':
      return 'french';
    case 'england':
    case 'usa':
      return 'english';
    case 'belgium':
      return ['french', 'dutch'];
    default:
      return 'swahili';
  }
})();

CoffeeScript doesn't force you to add a default else clause, although it is a good programming practice to always add one, just in case.

 

Chained comparisons


CoffeeScript borrowed chained comparisons from Python. These basically allow you to write greater than or less than comparisons like you would in mathematics, as shown here:

CoffeeScript

JavaScript

age = 41

alert 'middle age' if 61 > age > 39
var age;

age = 41;

if ((61 > age && age > 39)) {
  alert('middle age');
}
 

Block strings, block comments, and strings


Most programming books start with comments, and I thought I would end with them. In CoffeeScript, single line comments start with #. The comments do not end up in your generated output. Multiline comments start and end with ###, and they are included in the generated JavaScript.

You can span a string over multiple lines using the """ triple quote to enclose it.

 

Summary


In this chapter, we started looking at CoffeeScript from JavaScript's perspective. We saw how it can help you write shorter, cleaner, and more elegant code than you normally would in JavaScript and avoid many of its pitfalls.

We came to realize that even though CoffeeScripts' syntax seems to be quite different from JavaScript, it actually maps pretty closely to its generated output.

Later on, we delved into some of CoffeeScripts' unique and wonderful additions, like list comprehensions, destructuring assignment, and its class syntax, as well as many more convenient and powerful features such as string interpolation, ranges, splats, and array slicing.

My goal in this chapter was to convince you that CoffeeScript is a superior alternative to JavaScript, and I have tried to do so by showing the differences between them. Although I have previously said "it's just JavaScript", I hope that you'll appreciate that CoffeeScript is a wonderful and modern language in its own right, with brilliant influences from other great scripting languages.

I can still write a great deal about the beauty of the language, but I feel that we have reached the point where we can dive into some real world CoffeeScript and get to appreciate it "in the wild", so to speak.

So, are you ready? Let's get started then and get CoffeeScript installed.

About the Author

  • Michael Erasmus

    Michael Erasmus has been developing software for over 10 years. He has been a C# programmer for quite a few of them, but has luckily been enlightened enough to become an open source zealot during the last few years. The most loved tools in his utility belt are Ruby and Rails, Linux, MongoDB, Vim, jQuery, and CoffeeScript. He's interested in all manner of science and technology, but tends to dwell on things such as elegant and eccentric programming languages, machine learning and statistics, web development, Internet startups, and civic hacking. He is currently working at 22seven.com, building a service that will help change people's behavior and do more with the money they have. When he's not sitting in front of the computer, he likes pulling faces to amuse his baby son, apologizing to his wonderful wife for sitting in front of a computer all day, or arguing endlessly with friends, family, colleagues, and random strangers. He lives near the beach in Muizenberg, Cape Town and loves it.

    Browse publications by this author

Latest Reviews

(2 reviews total)
I am in the process of going through the book, but so far am finding it an excellent resource.
Het boek helpt me wel, maar de inhoud is wel verouderd, en er staan gewoon fouten in, die niet verbeterd worden in een erratum of zo.
Book Title
Access this book, plus 7,500 other titles for FREE
Access now