CoffeeScript: The Final Chapter

Spread the word
Tweet about this on TwitterShare on Google+Share on FacebookPin on PinterestShare on RedditShare on TumblrEmail this to someonePrint this page

In the last two posts Getting Started and Never Looking Back and Continuing Down the Rabbit Hole, we looked at a lot of the basic syntax differences between CS and JS and how those differences are more readable and less typing. In this post, we’ll continue to look at these features and at the end I’ll have some kickass references for you if you wish to learn more.

CoffeeScript Operators

Using CS or perusing someone’s CS code you will notice a number of operators that will be unfamiliar or even foreign. Let’s try to get them out in the open real quick.

  • is and isnt
  • ?
  • not
  • and and or
  • yes or on
  • no or off
  • And some new ones for me
    • **
    • //
is and isnt

These replace === and !==. There is no simple is equal to or not equal to in CS. Using the triple equals, if you are not familiar not only test that two values are equal, but also that they are the same Class or type. i.e.

  0 == 0     //=> true
  0 == "0"   //=> true
  0 == false //=> true
  1 == true  //=> true

  0 === "0"   //=> false
  0 === 0     //=> true
  0 === false //=> false
  1 === true  //=> false

  // and of course everyone's favorite JS quirk
  null == undefined  //=> true
  null === undefined //=> false

With the double equals its like were testing the appearance of something rather than all the attributes. 0 looks like "0" so it must be equal, but with the triple equals JS digs deeper. 0 looks like "0" but one is an integer and one is a string. Hey, what are you trying to pull here?! Thanks for baring with me on that tangent, but this is good stuff to know if you’re just getting into programming in general. Every language I’ve programmed in has the == and ===; PHP, Ruby, JavaScript and ActionScript.

So if we wanted to do these tests in CS… too bad. CS makes the decision for us that when we test 0 and "0" we don’t just want to test that they look the same, but actually are the same. I’ve never actually needed the double equals ever and the only reason I ever used them in straight JS was it was because it’s one less character.

So then why am I OK with typing the extra character when checking isnt instead of just using !=? Well, because typing isnt for me is more natural then shift + 1 and then reaching for = sign.

the question mark (?)

This is one of the coolest aspects of CoffeeScript. When you have a variable you can use the ? operator to test if that variable has been set. ? will return false if that variable null or undefined. This is a nice, handy and short method of determining whether something exists or not.

We saw this example in the last post and it illustrates the use of ? perfectly:

  rome = 'empire'

  destroy_rome() if rome?
  expand_carthage_influence() unless rome?

Here because rome is being set to “empire” the destroy_rome() method will be ran and expand_carthage_influence() will not be. This compiles down into:

  var rome;

  rome = 'empire';

  if (rome != null) {
    destroy_rome();
  }

  if (rome == null) {
    expand_carthage_influence();
  }

Essentially ? cuts out != null from our code. Pretty cool, huh? But let’s look at an even cooler use of the question mark operator.

  general =
    name: 
      first: "Hannibal"
      last: "Barca"
    country: "Carthage"
    arch_enemy: "Rome"
    make_pledge: () -> "destroy Rome"

  console.log general.name?.first
  # => "Hannibal"

  console.log general.sack_rome()
  # => End of world as we know it or rather: "TypeError: undefined is not a function" 

  console.log general.sack_rome?()
  # => undefined

general.name?.first will actually check that general has the property name set before it attempts to call general.name.first. Preventing your code from exploding on you because of an undefined value. Possibly even more helpful is this functionality with functions. Simply calling general.sack_rome() returns the error undefined is not a function and all your code breaks horribly. Worst day ever! Yet simply by adding the ?, CS tests that this method exists on general before trying to call it.

to not or not to not

Ok, pretty stupid, but it’s a fair statement. I haven’t been using the not operator because it’s three additional key strokes to avoid the !. I don’t quite understand it but there you have it. Could it be simply to be more readable? I don’t think so because everyone whose done any type of programming is aware of and has used the ! with their if statements.

Also a number of times I feel like I have to wrap the not <statement> in parentheses if using multiple test statements.

  if bob and (not fred)
    console.log "This is Bob!"

Moral of the story; you know what it is and you can choose to use it or not.

and/or

and is meant to replace && and or to replace the ||. An argument could be made that this is the same situation as the not operator, but I would defend the use of these two. Much like the isnt operator, these avoid having to hit shift + 7 or shift + \.

the rest

ok, rapid fire:

  • yes and on equal true
  • no and off equal false
  • ** equals Math.pow()
    • example: a ** b
    • => Math.pow(a, b)
  • // equals Math.floor()
    • example: a // b
    • => Math.floor(a / b)

String Interpolation

So for those of you that have not programmed in ruby or CoffeeScript before, you may not know what this is. Easy answer… time saver. In plain JavaScript, if you want to build a string that uses variables then you have to concatenate the string elements with your variables to create a final product string, like so:

Javascript

  var generals = ["Hannibal", "Caesar", "Alexander"];
  var territories = ["Italy", "Gaul", "the known world"];

  for(var i=0; i < generals.length; i++) {
    console.log("This man, " + generals[i] + " conquered " + territories[i] + ".");
  }

  // => This man, Hannibal conquered Italy.
  // => This man, Caesar conquered Gaul.
  // => This man, Alexander conquered the known world.

What a pain! But with CS this becomes so much easier. Firstly you must use double quotes for this to work, (this is also the case in ruby) and then you signal that a variable is going to be used by enclosing it within #{}.

Again this is exactly how you would do String Interpolation in ruby. Are we seeing a pattern?

Let’s take a look:

CoffeeScript

  generals = ["Hannibal", "Caesar", "Alexander"]
  territories = ["Italy", "Gaul", "the known world"]

  log_conquered i + 1, general for general, i in generals

  log_conquered = (i, general) ->
    console.log "This man, #{general} conquered #{territories[i]}."

  # => This man, Hannibal conquered Italy.
  # => This man, Caesar conquered Gaul.
  # => This man, Alexander conquered the known world.

Switch Statements

switch statements in CS also mimic how they’re done in ruby. By using the when, then and else we can tighten up the normal switch in JS. Let’s look at how we would write this in JS:

JavaScript

  switch(general) {
    case 'Hannibal':
      conquer_italy();
      break;
    case 'Caesar':
      conquer_gaul();
      defeat_pompey();
      break;
    case 'Alexander':
      conquer_known_world();
      break;
    default:
      conquered_by(general);
  }

And converting to CoffeeScript:

  switch general
    when 'Hannibal'  then conquer_italy()
    when 'Caesar'    
      conquer_gaul()
      defeat_pompey()
    when 'Alexander' then conquer_known_world()
    else
      conquered_by(general)

Notice that we do not need to break? In JS this break; tells the code that it shouldn’t go any further. In CS, due to the white-space dependency, this is already assumed by the next when that is tabbed out, just as in the : after the case 'some_string'. As in most things CoffeeScript, you do not need the parentheses for the switch function or the curly braces and of course get rid all our semi-colons. Lastly notice that default: is replaced by else. This, I feel is just for readability in the sense that CS tries to be like plain English. when something then do this else do this other thing.

Function Binding

This is a pretty big deal, at least for me and probably anyone whose done a lot of complex JavaScript. This basically refers to this scoping throughout your code. Now if your JS is mainly just a little bit of extra pizazz to a website, then Function Binding probably won’t be that impressive or important to you. Where it becomes super helpful is when dealing with Classes, complex Object Literals and nested anonymous functions or callback methods. Let’s take a look:

JavaScript

  var General = Class.extend({
    name: "Hannibal",
    accomplishments: [],

    get_accomplishments: function(dates) {
      var attrs = {
        name: this.general.name
        date_range: dates
      };

      // good ol' jQuery ajax method
      $.ajax({
        url: '/accomplishments',
        type: 'GET',
        dataType: 'json',
        data: attrs,
        success: function(response) {
          // in this scenario the 'this' is scoped 
          // to the 'success' function 
          // and thus the following will probably break
          this.name += " the Great";
          this.accomplishments = response;
          this.announce_greatness();
      });
    },

    announce_greatness: function() {
      var alert_str = "#{this.name} has done the following great acts:\n\n";
      $.each(this.accomplishments, function(i, accomplishment) {
        alert_str += "#{accomplishment}\n";
      }
      alert(alert_str);
    } 
  });
    
  var hannibal = new General();
  hannibal.get_accomplishments();

When looking at the get_accomplishments() method for the General class, the success callback will be a problem. this is now scoped to that anonymous function rather than the class itself as we would expect. So how does CoffeeScript fix this? Let’s find out:

CoffeeScript

  class General
    name: "Hannibal"
    accomplishments: []

    get_accomplishments: (dates) ->
      attrs =
        name: this.general.name
        date_range: dates
      # good ol' jQuery ajax method
      $.ajax
        url: '/accomplishments'
        type: 'GET'
        dataType: 'json'
        data: attrs
        success: (response) =>
          @name += " the Great"
          @accomplishments = response
          @announce_greatness()

    announce_greatness: ->
      alert_str = "#{this.name} has done the following great acts:\n\n"
      $.each this.accomplishments, (i, accomplishment) -> alert_str += "#{accomplishment}\n"
      alert alert_str
    
  
  hannibal = new General()
  hannibal.get_accomplishments()

Using the fat arrow (=>) on the success callback we now bind this to the class, but we do not reference it any longer with this, but rather using an @ symbol. So in our plain JS above, wherever (in the success callback) we saw this.something, we replace it with @something.

When compiling down to JS, CS creates a variable _this and within the method using the fat arrow it replaces this.something with _this.something. Pretty clever.

Some Final Cool Stuff

So that’s pretty much all the big stuff that you should know too use CoffeeScript and use it to its fullest potential. Yet there are some other really awesome features that I should hit that didn’t really fit anywhere else in the last three posts.

Splats

This is a super-cool feature with function/method parameters. Basically if you are not sure how many arguments are going to be passed to your function or method at any time but know that you’re going to need to do something with them, then you need splats. This done by adding three periods on the last parameter. Here’s how they work:

  build_empire = (name, regions...) ->
    new Empire
      name: name
      regions: regions

  $ ->
    carthage = build_empire 'Carthage', 'North Africa', 'Sicily', 'Sardinia', 'Spain'
    rome     = build_empire 'Rome', 'Italy', 'Gaul', 'Spain', 'Sicily', 'Greece', 'Syria', 'Egypt', 'North Africa', 'Briton'
    persia   = build_empire 'Persia', 'Iraq', 'Syria', 'Iran', 'Afganistan'

Notice how every call to build_empire() function has a different number of arguments passed to it, but all three will work and will do exactly as we want it to. Our first expected parameter passed to the build_empire() function will be the name of the empire. (i.e. Carthage, Rome and Persia) Every other parameter will be forced into a variable called regions. regions will be an Array and every parameter after the first (set to name) will be just another item in that array.

So carthage.regions will equal ['North Africa', 'Sicily', 'Sardinia', 'Spain'] and rome.regions will equal ['Italy', 'Gaul', 'Spain', 'Sicily', 'Greece', 'Syria', 'Egypt', 'North Africa', 'Briton'], etc.

Defaults for Parameters

Finally we can do this in JavaScript, with the help of CoffeeScript that is. In Ruby, PHP, ActionScript and even SCSS we’ve had this ability since forever, but JavaScript has been upsetting-ly lacking. Let’s take a look:

  hello_to = (first, to='you') ->
    alert "Hello to #{first} and #{to}"

  hello_to 'World', 'Bob'
  # => Hello to World and Bob

  hello_to 'Fred'
  # => Hello to Fred and you

This compiles down to:

  var hello_to;

  hello_to = function(first, to) {
    if (to == null) {
      to = 'you';
    }
    return alert("Hello to " + first + " and " + to);
  };

  hello_to('World', 'Bob');

  hello_to('Fred');
Multi-line Strings and Comments

Multi-line strings are super nice when you’re adding blocks of HTML to the DOM via JS. With these you can write this HTML just as you would in a normal HTML file, nice and readable. Multi-line strings are done by opening with three double quotes and closed with an additional set of three.

  my_html = """
    <div class="box">
      <p>All that Jazz</p>
      <ul class="types">
        <li>Bebop</li>
        <li>Smooth</li>
        <li>Blues</li>
      </ul>
    </div>
  """

  $('.box-container').append my_html

Notice that we can use double quotes within this multi-line quotes block. CS automatically escapes the quotes within this block for you.

Multi-line comments work the same way but with the number symbol (#) instead of double quotes.

  ###
    Gets the person's attributes and logs out a welcome message

    Parameters:
      => attrs::Object

    Returns:
      => Array
  ###
  my_function = (attrs) ->
    {name, age, weight, height} = attrs
    console.log "Hello #{name}, we see that your age is #{age}"

    [weight, height]
Chained Comparisons

Simple way of verifying a value falls within a range.

  age = 55

  young_at_heart() if 45 > age > 70

Resources

  • coffeescript.org
    This is what I almost always reference while working in CoffeeScript, it’s definitely the first place I look. I tell everyone to check there first if they have questions. It’s simple, easy to understand and the table of contents helps you navigate quickly to what you’re looking for.
  • Better JS with CoffeeScript – Sam Stephenson
    If your still on the fence about CoffeeScript, then you should watch this video. I started playing round and loving CoffeeScript minutes after watching this. It is a great introduction to CS and spotlights all the great features in less than 45 minutes. Enjoy.
  • js2coffee.org
    Simple way to convert existing JS code to CoffeeScript and vise versa. Just found out… you can install it locally using npm.
Spread the word
Tweet about this on TwitterShare on Google+Share on FacebookPin on PinterestShare on RedditShare on TumblrEmail this to someonePrint this page