So I'm learning CoffeeScript at work since the project I'll be working on uses that for most of its JavaScript generation. My initial thought was, "Why learn a language that generates JS"? I mean, I can just write the JS myself. Well, the more I look into it, the more I appreciate CoffeeScript. Yes, the syntax is a bit odd compared to traditional JS, but it's in line with Ruby. The concise nature is really appealing.
To get started you need a working copy of Node.js. Install that, then run the following command:
$> npm install coffee-script
You can check your installation by running:
$> coffee -v
CoffeeScript version 1.3.1
Now you have two ways to use CoffeeScript. You can start the interactive REPL by typing:
$> coffee
coffee>
From here you can enter CoffeeScript commands to execute.The more common approach would be to author a .coffee file and compile it via:
$> coffee -c foo.coffee
This will produce a foo.js file that can be executed via:
$> node foo.js
You also have the option of just running a CoffeeScript file from the command line by dropping the '-c' option. This will execute the script without compiling the extra JS file.
Now let's take a look at some actual CoffeeScript. Create a file called foo.coffee and enter the following:
# Base class
class Automobile
constructor: (options) ->
@make = options?.make ? "unknown"
@model = options?.model ? "unknown"
@trimLevel = options?.trimLevel ? "unknown"
@displacement = options?.displacement ? "unknown"
@cylinders = options?.cylinders ? "unknown"
@transmission = options?.transmission ? "automatic"
toString: () ->
console.log(" make: " + @make + "\n" +
" model: " + @model + "\n" +
" trimLevel: " + @trimLevel + "\n" +
" displacement: " + @displacement + "\n" +
" cylinders: " + @cylinders + "\n" +
" transmission: " + @transmission + "\n")
# Car class
class Car extends Automobile
constructor: (options, @bodyStyle="sedan") ->
super(options)
toString: () ->
super console.log(" bodyStyle: " + @bodyStyle)
# Truck class
class Truck extends Automobile
constructor: (options, @towingCapacity=2000) ->
super(options)
toString: () ->
super console.log("towingCapacity: " + @towingCapacity)
# Create an array of autos, some with properties set
c1 = new Car({make:"Nissan", model:"Altima", trimLevel:"SL", displacement:3.5, cylinders:6})
c2 = new Car({make:"Volvo", model:"T5", displacement:3.5, cylinders:5, transmission:"5-speed"})
t1 = new Truck ({make:"Ford", model:"F150", trimLevel:"Laredo", displacement:5, cylinders:6, towingCapacity:9500})
autos = [ c1, c2, t1]
# Loop through the 'cars' array and print out each object
auto.toString() for auto in autos
This is 42 lines of code including comments and blank lines. This compiles to:
// Generated by CoffeeScript 1.3.1
(function() {
var Automobile, Car, Truck, auto, autos, c1, c2, t1, _i, _len,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
Automobile = (function() {
Automobile.name = 'Automobile';
function Automobile(options) {
var _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
this.make = (_ref = options != null ? options.make : void 0) != null ? _ref : "unknown";
this.model = (_ref1 = options != null ? options.model : void 0) != null ? _ref1 : "unknown";
this.trimLevel = (_ref2 = options != null ? options.trimLevel : void 0) != null ? _ref2 : "unknown";
this.displacement = (_ref3 = options != null ? options.displacement : void 0) != null ? _ref3 : "unknown";
this.cylinders = (_ref4 = options != null ? options.cylinders : void 0) != null ? _ref4 : "unknown";
this.transmission = (_ref5 = options != null ? options.transmission : void 0) != null ? _ref5 : "automatic";
}
Automobile.prototype.toString = function() {
return console.log(" make: " + this.make + "\n" + " model: " + this.model + "\n" + " trimLevel: " + this.trimLevel + "\n" + " displacement: " + this.displacement + "\n" + " cylinders: " + this.cylinders + "\n" + " transmission: " + this.transmission + "\n");
};
return Automobile;
})();
Car = (function(_super) {
__extends(Car, _super);
Car.name = 'Car';
function Car(options, bodyStyle) {
this.bodyStyle = bodyStyle != null ? bodyStyle : "sedan";
Car.__super__.constructor.call(this, options);
}
Car.prototype.toString = function() {
return Car.__super__.toString.call(this, console.log(" bodyStyle: " + this.bodyStyle));
};
return Car;
})(Automobile);
Truck = (function(_super) {
__extends(Truck, _super);
Truck.name = 'Truck';
function Truck(options, towingCapacity) {
this.towingCapacity = towingCapacity != null ? towingCapacity : 2000;
Truck.__super__.constructor.call(this, options);
}
Truck.prototype.toString = function() {
return Truck.__super__.toString.call(this, console.log("towingCapacity: " + this.towingCapacity));
};
return Truck;
})(Automobile);
c1 = new Car({
make: "Nissan",
model: "Altima",
trimLevel: "SL",
displacement: 3.5,
cylinders: 6
});
c2 = new Car({
make: "Volvo",
model: "T5",
displacement: 3.5,
cylinders: 5,
transmission: "5-speed"
});
t1 = new Truck({
make: "Ford",
model: "F150",
trimLevel: "Laredo",
displacement: 5,
cylinders: 6,
towingCapacity: 9500
});
autos = [c1, c2, t1];
for (_i = 0, _len = autos.length; _i < _len; _i++) {
auto = autos[_i];
auto.toString();
}
}).call(this);
This JavaScript is 99 lines including blank lines.
Now admittedly, this example doesn't really do much, but it does show how easy it is to define classes, extend them, override methods, and perform some simple operations upon them. I think that the CoffeeScript is really easy to read, and the intent of the code is pretty straightforward. That's one of the points of CoffeeScript; The code should be self documenting. I think that might be true for people familiar with the CoffeeScript syntax, but a complete novice would still need some comments so that's why I added a few.
Like I stated before, I really like the terse nature of the language. Gone are all of the unnecessary parenthesis and semicolons. This does mean though that your indentation are significant as that's how blocks of code are grouped. The CoffeeScript file is 57 less lines of code, and that alone is reason to switch to CoffeeScript in my book!
I encourage you to stop by coffeescript.org and check it out.