Rocking Out With CoffeeScript
Even though CoffeeScript is a new language, you’ll learn it very quickly. You should, since it’s only JavaScript flaunting with some flashy clothes, after all. It reads like Ruby or Python, but compiles down to pure, non-fluffy JavaScript. Today, we’re going to take a look at why everyone is talking about CoffeeScript.
A Word From the Author
With the advent of powerful JavaScript engines, like V8, JavaScript has shed its stigma of a gimped tool for juvenile interactions and morphed into quite a powerhouse. It has even jumped from client side applications to server side, node.js for instance. The fact that it adheres to a pretty nifty, prototype based ideology doesn’t hurt it either. There is no doubt that JavaScript is indeed a critical language now and for the foreseeable future.
But I’ve always felt the syntax itself to be a bit kludgy. After working with a mix of Ruby and Python over the past couple of years, I’ve been finding JavaScript’s semi-colon infused, parentheses dependent, verbose syntax to be tedious. And from what I can gather, I’m not alone in feeling this way. This is where CoffeeScript comes to the rescue!
What is CoffeeScript?
CoffeeScript compiles down to raw JS.
CoffeeScript is essentially just a syntactic rewrite of JavaScript. The core language itself stays the same, with small semantic enhancements. The syntax is modified, modeled after Python and Ruby.
Remember that the CoffeeScript compiler outputs clean JavaScript that not only follows best practices and is eminently readable but also passes JSLint. This means that you don’t have to worry about compatibility down the line. In the worst case scenario of this project dying, you can just pick up the pristine JS that CoffeeScript generates and move on with your code. You aren’t locked into this environment.
This may seem like an alien concept but under the web development umbrella, we’ve already seen our fair share of this ideology. HAML is but a new way of writing HTML while SASS does the same for CSS. All of them clean up the structure and syntax of their languages making them more easier to work with and thus boosting our productivity.
Some Quick Code
You’re probably wondering how the code itself looks so here is a quick peek:
- index = (list, target) ->
- [low, high] = [0, list.length]
- while low < high
- mid = (low + high) >> 1
- val = list[mid]
- return mid if val is target
- if val < target then low = mid + 1 else high = mid
- return -1
This is a quick implementation of a binary search. Don’t try to parse the code itself right now. Just try to familiarize yourselves with the syntax.
Below is the JavaScript code that CoffeeScript generates:
- var index;
- index = function(list, target) {
- var high, low, mid, val, _ref;
- _ref = [0, list.length], low = _ref[0], high = _ref[1];
- while (low < high) {
- mid = (low + high) >> 1;
- val = list[mid];
- if (val === target) {
- return mid;
- }
- if (val < target) {
- low = mid + 1;
- } else {
- high = mid;
- }
- }
- return -1;
- };
Pros and Cons
Here are some quick advantages and disadvantages of using CoffeeScript. This isn’t comprehensive by any means but I think this is sufficient to get a quick overview of the system.
Yays
- Python style whitespacing
- Ruby styled lightweight syntax
- Concise function declarations
- JSLint approved
- Class based inheritance
There are, of course, numerous other points including semantic and syntactic enhancements.
Nays
- Slight learning curve involved
- Deployment, depending on your route, may be a chore
- You’ll need a basic knowledge of JS for debugging purposes. You can’t directly start here, naturally.
Getting Started
The official methods to get started include a command line utility that runs under node.js and simply downloading the source and installing it. Nothing much to guide here. Get the node.js utility and use
npm install coffee-script
[or for the source, bin/cake install
] to install and get started.
The situation with Windows is slightly more complicated. There is no straight forward way to get node.js or the source installed on Windows [outside of Cygwin]. Never fret though. A number of enterprising people have written compilers that work natively on Windows. I’ve included a few below:
Note that the compiler, in compiled JavaScript form, is also bundled with the source, if you’re interested. It’s present under the extra directory with an obvious name.
With that out of the way, we’re now going to take a look at a handful of things that show you how CoffeeScript makes JavaScript easier to consume!
Use of Whitespace
The first thing you’ll need to know is how CoffeeScript uses whitespace effectively to simplify the syntax. People with a Python background will find this trivial but for the others, here is a quick explanation.
First up, you need not end every line with a semi-colon. Ending a line is automatically interpreted to be the end of that statement. For example, this..
- numbers = [0, 1, 2, 3]
- name = "NetTuts+"
.. compiles down to this:
- var name, numbers;
- numbers = [0, 1, 2, 3];
- name = "NetTuts+";
Next, you’ll be happy to know that you can do away with curly braces. Those numerous braces for opening and closing a block? Everything’s out. In CoffeeScript, you use Python-esque indentation to signify the beginning and ending of a block.
CoffeeScript doesn’t require unnecessary parentheses or curly braces.
Here is a quick example. Disregard everything but the indentation for now. We’ll get to the rest a little later below:
- if chasedByCylons
- runForYourLife()
.. compiles down to
- if (chasedByCylons) {
- runForYourLife();
- }
If you’re still a little confused, don’t worry. The syntax will start making more sense once we get to know the language better.
Nifty, Semantic Aliases
CoffeeScript provides a number of aliases for operators and keywords to make the code more readable and intuitive. Let’s take a look at some of them now.
First, the comparison operators:
is
maps to===
isnt
compiles to!==
==
and!=
compile to===
and!==
respectively [As a best practice]
Let’s see them in action quickly.
- if pant is onFire
- lookForWater()
- if game isnt good
- badMouth();
..which compiles to..
- if (pant === onFire) {
- lookForWater();
- }
- if (game !== good) {
- badMouth();
- }
Pretty easy to read, no? Now, on to how logical operators are mapped.
and
maps to&&
or
is an alias for||
not
compiles down to!
Building on our previous code:
- if pant is onFire and not aDream
- lookForWater()
- if game isnt good or haughtyDevs
- badMouth();
..which compiles to..
- if (pant === onFire && !aDream) {
- lookForWater();
- }
- if (game !== good || haughtyDevs) {
- badMouth();
- }
Conditionals
As you’ve already seen above, the basic
if/else
construct behaves the same as in normal JavaScript, sans the parentheses and curly braces. We’ll look at some variations below.- if tired and bored
- sleep()
- else
- jog()
- // Raw JS below
- if (tired && bored) {
- sleep();
- } else {
- jog();
- }
And here’s how the ternary operator is handled:
- activity = if sunday then isChilling else isWorking
- // Raw JS below
- activity = sunday ? isChilling : isWorking;
An additional semantic enhancement is with the
unless
keyword. This functions as the exact opposite ofif
.- keepRunning() unless tired
- keepWorking unless focus is extremelyLow
And the compiled JavaScript…
- if (!tired) {
- keepRunning();
- }
- if (focus !== extremelyLow) {
- keepWorking;
- }
Switch-Case
Switch statements can be a little obtuse in JavaScript. CoffeeScript provides an intuitive wrapper around this construct.
It begins with the
switch
keyword, as expected, followed by the variable whose value we’re checking. Each case or possible value is preceded by the when
keyword followed by the statements to execute if it’s a match.There’s no need to add abreak
statement at the end of every case statement: CoffeeScript does this automatically for you.
- switch time
- when 6.00
- wakeUp()
- jotDownList()
- when 9.00 then startWorking()
- when 13.00 then eat()
- when 23.00
- finishUpWork()
- sleep()
- else doNothing()
The syntax should be fairly self explanatory if you already know the equivalent in JavaScript. The only point to note here is the use of the
then
keyword. It’s used to separate the condition from the expression without starting a new line. You can use then for the other conditional statements as well as loops too.
Here’s the JS that CoffeeScript generates for you:
- switch (time) {
- case 6.00:
- wakeUp();
- jotDownList();
- break;
- case 9.00:
- startWorking();
- break;
- case 13.00:
- eat();
- break;
- case 23.00:
- finishUpWork();
- sleep();
- break;
- default:
- doNothing();
- }
Basic Loops
Looping is another essential construct for your typical JavaScript code. Be it looping through numbers in an array or nodes in the DOM, you’re always in need of looping through collections.
CoffeeScript provides a very flexible
while
loop that can be modified to function as a generic for
or do-while
loop.- while work > time then freakOut()
- while time > work
- relax()
- mozyAround()
- // Raw JS
- while (work > time) {
- freakOut();
- }
- while (time > work) {
- relax();
- mozyAround();
- }
until
is another semantic enhancement and is equivalent to while not.
A quick example below:- workOut() until energy < exhaustion
- // Raw JS
- while (!(energy < exhaustion)) {
- workOut();
- }
Looping Through Collections
Looping over arrays is pretty easy. You’ll need to use the
for..in
construct to step through the array. Let me show you how:- sites = ['CodeCanyon','ThemeForest','ActiveDen']
- for site in sites
- alert site
If you prefer the statements to be in the same line:
- sites = ['CodeCanyon','ThemeForest','ActiveDen']
- alert site for site in sites
CoffeeScripts compiles these to basic
for
loops like so. Note that in line with best practices, the length of the array is cached beforehand.- var site, sites, _i, _len;
- sites = ['CodeCanyon', 'ThemeForest', 'ActiveDen'];
- for (_i = 0, _len = sites.length; _i < _len; _i++) {
- site = sites[_i];
- alert(site);
- }
Iterating over associate arrays [or hashes or dictionaries or key-value pairs] is just as easy with the
of
keyword.- managers = 'CodeCanyon': 'Jeffrey Way', 'ThemeForest': 'Mark Brodhuber', 'ActiveDen': 'Lance Snider'
- for site, manager of managers
- alert manager + " manages " + site
As expected, the above compiles down to a basic for loop as shown below:
- var manager, managers, site;
- managers = {
- 'CodeCanyon': 'Jeffrey Way',
- 'ThemeForest': 'Mark Brodhuber',
- 'ActiveDen': 'Lance Snider'
- };
- for (site in managers) {
- manager = managers[site];
- alert(manager + " manages " + site);
- }
Functions
Creating and using functions is extremely easy under CoffeeScript. To define a function, you list the parameters it takes and then go on with the function's body. Here, let me show you how:
- playing = (console, game = "Mass Effect") ->
- alert "Playing #{game} on my #{console}."
- playing 'Xbox 360', 'New Vegas'
This is the basic syntax behind creating and using functions. The default value for parameters can be defined inline. CoffeeScript generates the code to check whether a value has been passed in or not.
Invoking a function is just as easy. There's no need for parentheses: pass in the parameters one after the other.
As always, here's the generated code for your reference:
- var playing;
- playing = function(console, game) {
- if (game == null) {
- game = "Mass Effect";
- }
- return alert("Playing " + game + " on my " + console + ".");
- };
- playing('Xbox 360', 'New Vegas');
Embedding Raw JavaScript
Sometimes, you may have no other choice but to use raw JavaScript inside your CoffeeScript code. Hopefully, these instances should be far and few between but this has been taken into account as well.
You can inject raw JS into your code by wrapping it with grave accents, also known as a backquote or backtick. Anything passed in thus will be completely untouched by the CoffeeScript compiler.
- rawJS = `function() {
- return someSuperComplexThingie;
- }`
- // which nets you
- var rawJS;
- rawJS = function() {
- return someSuperComplexThingie;
- };
What Happens to My Libraries?
Nothing happens to them, they can stay exactly where they are. CoffeeScript works seamlessly with any third party library, big or small, because it simply compiles to raw JavaScript. You'll just have to reformat and/or refactor your code very slightly but other than that, incompatibilities shouldn't be a point of concern.
So instead of writing this:
- $(document).ready(function() {
- elemCollection = $('.collection');
- for (i=0; i<=elemCollection.length;i++)
- {
- item = elemCollection[i];
- // check for some random property here. I am skipping the check here
- colortoAdd = item.hasProperty()? yesColor : noColor;
- // I'm quite aware there are better ways to do this
- $(item).css ('background-color', colortoAdd);
- }
- });
... you'd write..
- $(document).ready ->
- elemCollection = $('.collection')
- for item in elemCollection
- colortoAdd = if item.hasProperty() then yesColor else noColor
- $(item).css 'background-color', colortoAdd
That's All Folks
And we've come to an end. I haven't covered a number of higher levels topics, classes for example, because they're well beyond the scope of an introductory article. Look for some advanced CoffeeScript tutorials down the road!
I think CoffeeScript has changed the way I write JavaScript and, after reading this, I hope it has changed yours too. Questions? Nice things to say? Criticisms? Hit the comments section and leave me a comment. Happy coding and thank you so much for reading!
0 comments:
Post a Comment