Playing with CoffeeScript

I’ve been fiddling with Coffeescript, a nifty language for writing Javascript – well, really it’s more like a pre-compiler than a language; it compiles directly to readable javascript (including comments!) and generally one Coffeescript statement produces one javascript statement.

So why would you use it? Because it bypasses some of the horribleness of Javascript syntax, and implements a few handy patterns, like anonymous function creation, in much clearer code.

For example, the following Coffeescript:

square: (x) ->
alert 'squaring: ' + x
x * x

converts to the following javascript:

square: function square(x) {
  alert('squaring:' + x);
  return x * x;
}

There are many more examples at the Coffeescript home page.

I’m not 100% sold on this, as I’m still learning (proper) Javascript, and this amplifies some of my ignorance. For example, I really struggle with ‘this’ and functions/objects – and while Coffeescript automatically enforces some good Javascript behaviour, when I do something wrong it’s a bigger than usual struggle to work out why.
A longer example: I’ve been playing with Raphael (and JQuery) and decided to do some fiddling in Coffeescript:

app: {
  init: ->
    app.paper: Raphael('playspace',320,200)
    app.draw_circle()
    app.draw_square()

  # simple circle with event-based on-click event
  draw_circle: ->
    circle: app.paper.circle(50,40,30)
    circle.attr("fill","#f00")
    circle.attr("stroke","#fff")
    $(circle.node).click((e) -> app.kick(e))

  # square with object-based on-click event
  draw_square: ->
    square: app.paper.rect(150,40,50,30)
    square.attr("fill","#0f0")
    square.attr("stroke","#fff")
    $(square.node).click((e) -> app.punt(square,e))

  kick: (e) ->
    app.paper.text(e.pageX + 10, e.pageY + 10, "Raphaël\nkicks\nbutt!")

  punt: (obj,e) ->
    obj.translate(10,10)
}

# make it globally visible - not really needed, handy for debugging
if window?
  window.APP: app

$(app.init)

The javascript version is:

(function(){
  var app;
  app = {
    init: function init() {
      app.paper = Raphael('playspace', 320, 200);
      app.draw_circle();
      return app.draw_square();
    },
    // simple circle with event-based on-click event
    draw_circle: function draw_circle() {
      var circle;
      circle = app.paper.circle(50, 40, 30);
      circle.attr("fill", "#f00");
      circle.attr("stroke", "#fff");
      return $(circle.node).click(function(e) {
        return app.kick(e);
      });
    },
    // square with object-based on-click event
    draw_square: function draw_square() {
      var square;
      square = app.paper.rect(150, 40, 50, 30);
      square.attr("fill", "#0f0");
      square.attr("stroke", "#fff");
      return $(square.node).click(function(e) {
        return app.punt(square, e);
      });
    },
    kick: function kick(e) {
      return app.paper.text(e.pageX + 10, e.pageY + 10, "Raphaël\nkicks\nbutt!");
    },
    punt: function punt(obj, e) {
      return obj.translate(10, 10);
    }
  };
  // make it globally visible - not really needed, handy for debugging
  (typeof window !== "undefined" && window !== null) ? (window.APP = app) : null;
  $(app.init);
})();

Now, this works, it’s a lot more readable than the Javascript version, and it’s nifty how Coffeescript wrapped everything in an anonymous function so as to not pollute the global namespace (except where I did so deliberately).

But this was about my 8th try.  I had endless problems getting the ‘click’ handlers to hook into the ‘kick’ and ‘punt’ methods.  I tried (initially) using ‘this.kick’ but it failed as when the click handler is called, this is bound elsewhere. I tried storing ‘this’ in a variable, but had pain with the fact that somewhere in the mess of anonymous function wrappers, ‘this’ never seemed to mean the right thing.

In the end, I hit on storing the whole thing as an object ‘app’ – I was already going to make it part of ‘window.APP’ but didn’t want to prefix all calls with ‘APP’… but in the end, that’s kind-of what I did, only the global APP variable isn’t actually needed, just the local ‘app’ variable.

Anyway, I’m sure there is a better way to do this – but I haven’t found it, and this one works. Now I have to decide if I want to keep playing with Coffeescript, having worked all this out, or go back to ugly old Javascript, where at least there are hundreds of net resources to help me when I get stuck!



4 Responses to “Playing with CoffeeScript”

  1.   jashkenas Says:

    Nice writeup. It’s very cool to see an example of using Raphael from CoffeeScript.

    The problem that you had with “this” is one of my least favorite parts of JavaScript. Unlike everything else in JS (which has proper lexical scope), the value of “this” within a function is the object that the function has been attached to.

    The benefit is that you can pull a function off one object and attach it to another, and it’ll work seamlessly. The downside is that if you pull a function off an object, say, to hand it to a click handler, it loses its notion of identity and it’s former value for “this”.

    The common way to address it is to set a local variable to “this” from the outside, and reference it through the closure, instead of “this”. So, your original:

    $(circle.node).click (e) -> this.kick e

    Becomes:

    me: this
    $(circle.node).click (e) -> me.kick e

    Which will work properly. However, CoffeeScript provides a convenience for defining functions that are bound to the current value of “this”, right on the spot where they’re declared, for use in cases like these.

    http://jashkenas.github.com/coffee-script/#fat_arrow

    Using the fat arrow, the example becomes:

    $(circle.node).click (e) => this.kick e

    Hope that helps.

  2.   korny Says:

    Thanks – that works!
    I’m still confused around how ‘this’ works – it’s not really a Coffeescript thing, more of a Javascript thing.
    For example, in my code above, I can change references in ‘app.draw_circle’ to use ‘this’ and they get ‘app’. Which makes sense, as they are called as ‘app.draw_circle()’
    But I can’t change references in ‘app.init’ to use ‘this’, for some reason the JQuery call ‘$(app.init)’ doesn’t set ‘this’ to ‘app’… I think that’s where a lot of my confusion started, as I’d change something in ‘draw_circle’ and it would work, then I’d change it in ‘init’ and it wouldn’t!

  3.   korny Says:

    In fact, I can clean everything up by putting in a second init, and then I can use ‘@’ (which is an alias for ‘this.’

    app: {
    init: -> app.__init()
    __init:
    @paper: Raphael('playspace',320,200)
    @draw_circle()
    @draw_square()

    Nice!

  4.   jashkenas Says:

    Right — when you pass the “app.init” function into jQuery (binding it to document.ready), you’re pulling the function off of the “app” object, and it loses its sense of “this”. So, another way to go is to keep your single init, and replace the final line with this:

    $(-> app.init())

Leave a Reply

CAPTCHA Image CAPTCHA Audio
Refresh Image