Don’t use fat arrows in CoffeeScript just because of »this«

New Coffeescript programmers usually struggle with understanding the differences between -> and => function definitions. In order to clarify this common case of confusion, it helps to look at how such functions are compiled down to JavaScript.

class A

    constructor: () ->
        @funcA()
        @funcB()

    funcA: () ->
        return 'funcA'

    funcB: () =>
        return 'funcB'

a = new A
var A, a,
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

A = (function() {
  function A() {
    this.funcB = __bind(this.funcB, this);
    this.funcA();
    this.funcB();
  }

  A.prototype.funcA = function() {
    return 'funcA';
  };

  A.prototype.funcB = function() {
    return 'funcB';
  };

  return A;

})();

a = new A;

By using ->, funcA is simply attached to the prototype of class A. When using fat arrows, however, CoffeeScript casts a shadow around the original function, using apply() to glue it to the class instance. Therefore such functions always have the same this (@) context, no matter where they are called. The difference may be tiny, but very important. In order to find out when to use which arrow style, two questions need to be asked:

  1. Do you use this (@) in the function?
  2. Do you want to execute the function later, possibly from a different scope?

If both questions were answered positive, then using => is the right choice.

A typical example might look like this:

class A

    constructor: () ->
        @name = 'CoffeeScript'
        @values = [1, 4, 9].map(@funcA)
        console.log(@values)

    funcA: () ->
        return @name

a = new A

This will break because funcA is implemented with -> and the function is called in the context of map, where @name won’t be defined. By using =>, it doesn’t matter where and how to call the method as its context is permanently bound to the object:

class A

    constructor: () ->
        @name = 'CoffeeScript'
        @values = [1, 4, 9].map(@funcA)
        console.log(@values)

    funcA: () =>
        return @name

a = new A

Mentioned in the article »Understanding Fat Arrows (=>) in CoffeeScript«, a good rule of thumb might be:

  • Use => when you want @ to be the object in which the method is defined.
  • Use -> when you want @ to be the object in which the method is executed.

Another interesting example, that deals with context and scope in CoffeeScript, shows why the differentiation keeps being important even in tiny scripts:

class A
    constructor: () ->
        a = () -> console.log(@)
        a()

a = new A()

The output will be the window object because a new scope is being created by declaring a -> function in the constructor of class A. A better approach would be to bind the method’s context to the object using a fat arrow:

class A
    constructor: () ->
        a = () => console.log(@)
        a()

a = new A()

Before using single or fat arrows, one has to ask the two important questions mentioned above in order to find out which arrow style fits best.