coffeescript  javascript  

Dec 14, 2014 • Michael Chen

JavaScript is the vital part of modern interactive web. However, JavaScript is not easy; it mixes the features of several languages. Some good, some bad. The syntax is Java-esque but the underlying concepts is totally different from Java. CoffeeScript is a mini-language that compiles into JavaScript. It brings an elegant Python or Ruby-like syntactic sugar for JavaScript and helps you to avoid some JavaScript pitfalls.

Here is an example of CoffeeScript:

# a function
square = (x) -> x * x

# an object
math =
  root: Math.sqrt
  square: square
  cube: (x) -> x * square x

# an array
list = [1..5]

# list comprehension in coffeescript
cubes = (math.cube num for num in list)

console.log cubes

The above examples are compiled into the following equivalent JavaScript:

var cubes, list, math, num, square;

square = function(x) {
  return x * x;
};

math = {
  root: Math.sqrt,
  square: square,
  cube: function(x) {
    return x * square(x);
  }
};

list = [1, 2, 3, 4, 5];

cubes = (function() {
  var _i, _len, _results;
  _results = [];
  for (_i = 0, _len = list.length; _i < _len; _i++) {
    num = list[_i];
    _results.push(math.cube(num));
  }
  return _results;
})();

console.log(cubes);

As you see, the code is shorter and more readable in CoffeeScript than in JavaScript. Besides, CoffeeScript add several sugars for JavaScript. For example, auto-generated list and list comprehension seen in the above code snippet. You may check the official site of CoffeeScript to see more examples.

There are still other good things of CoffeeScript. For instance, CoffeeScript warp the function by default to avoid global variable space contamination.

gcd = (x, y) ->
  [x, y] = [y, x % y] while y != 0
  return x

The above example will be compiled into:

(function() {
  var gcd;

  gcd = function(x, y) {
    var _ref;
    while (y !== 0) {
      _ref = [y, x % y], x = _ref[0], y = _ref[1];
    }
    return x;
  };
}).call(this);

Another feature of CoffeeScript is block regular expression, which supports better regex code. This is a regex pattern checking domain name in CoffeeScript:

domain_name = ///
   \b
   (
     # ftp://, http:// or https:// leadning part
     (ftp|https?)://[-\w]+(\.\w[-\w]*)+
   |
     # or, try to find a hostname
     (?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \. )+
     # top domain name
     (?-i: com\b
         | edu\b
         | biz\b
         | in(?:t|fo)\b # .int or .info
         | mil\b
         | net\b
         | org\b
         | [a-z][a-z]\b # two-letter country codes
      )
   ) ///

It is more readable than their JavaScript equivalent. Besides, you can add comment inside your regex pattern, which is an eye candy.

var domain_name = /\b((ftp|https?):\/\/[-\w]+(\.\w[-\w]*)+|(?i:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+(?-i:com\b|edu\b|biz\b|in(?:t|fo)\b|mil\b|net\b|org\b|[a-z][a-z]\b))/;

Since CoffeeScript will be compiled into JavaScript, JavaScript libraries are supported. For example, a client-side CoffeeScript code using jQuery:

$("p").hover(
  () ->
    $(@).css "background-color", "#ffff00"
  ,
  () ->
    $(@).css "background-color", "white"
)

Node.js libraries are supported as well. Let’s see a hello-world Express.js example written in CoffeeScript:

express = require 'express'
http = require 'http'

app = express()

app.get '/', (req, res) ->
  res.send "Hello, World!"

http.createServer(app).listen(4000)

Compile the example into JavaScript code and you’ll get a simple Node.js application.

If you want to give CoffeeScript a try, you can download coffee-script as a Node.js app and install it globally.

$ npm install coffee-script -g  # install CoffeeScript
$ coffee -c code.coffee         # compile code.coffee into code.js

Alternatively, you can try some CoffeeScript snippet on the CoffeeScript website. (At Try CoffeeScript region.)

Although CoffeeScript cannot totally eliminate the pitfalls of JavaScript, CoffeeScript brings you the good parts. “Writing in CoffeeScript; reading in JavaScript” becomes a possible mode to do JavaScript programming.