Scope in CoffeeScript - actionanand/coffeescript-practice GitHub Wiki

Introduction

Similar to JavaScript, CoffeeScript is a lexically scoped language. Put simply, it allows member functions (or child functions, methods etc.) to access their parent (object, function, class etc.). This works differently in different languages, but the principle remains the same - every inner level can access its outer levels.

In terms of CoffeeScript, this means that we don't need to write var before declaring a variable (we can't event if wanted to, trying to access var is reported as an error in CoffeeScript). Additionally, all CoffeeScript output is wrapped in an anonymous function. As the documentation says:

This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.

This behavior can be circumvented by directly accessing the window object and attaching properties to it. A cleaner alternative would be to use the CommonJS exports / module.exports approach. During the course, I decided to go for the window approach, for simplicity's sake.

Differences between JavaScript and CoffeeScript

One confusing aspect of JavaScript is its behavior when using closures (for example, for callbacks). While using callbacks (and closures in general) follows the same behavior in CoffeeScript, it has one additional feature to help normalize* this behavior - the => fat arrow operator. Essentially, it does the var self = this; "hack" automatically (although a bit differently):

CoffeeScript source

Account = (customer, cart) ->
  @customer = customer
  @cart = cart

  $('.shopping_cart').bind 'click', (event) =>
    @customer.purchase @cart

Compiled JavaScript

var Account;

Account = function(customer, cart) {
  this.customer = customer;
  this.cart = cart;
  return $('.shopping_cart').bind('click', (function(_this) {
    return function(event) {
    return _this.customer.purchase(_this.cart);
  };
  })(this));
};

In a manner of speaking, the fat arrow "transfers" the parent scope to the closure, preserving the context of @ (this).

Resources

Further reading

A bit more advanced, but an interesting read nevertheless

And a great book on the subject, by the same author