Understanding Fat Arrows (=>) in CoffeeScript

The fat arrows (=>) are special function expressions that confuse even the smartest of developers. Most JavaScript professionals know that closure changes the meaning of this (@ in CoffeeScript).

There’s no reason to be afraid of fat arrows in CoffeeScript. They are time savers (and clarity achievers) when it comes to the nested functions and jQuery event handlers. When they are applied to class methods, the good rule of thumb is: use => when we need @ to be the object in which method is written; use-> when we need @ to be the object in which method is executed.

The fat arrows (=>) are special function expressions that confuse even the smartest of developers. Most JavaScript professionals know that closure changes the meaning of this (@ in CoffeeScript).

Fat Arrows with Closures in CoffeeScript

For example, we have a class inside of which @ resolves to itself, but in a nested closure (a.k.a. anonymous function definition) the @ is window:

Fat Arrows with Closure in CoffeeScript
Fat Arrows with Closure in CoffeeScript

The CoffeeScript code:

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

a = new A
a.a()

The JavaScript code:

var A, a;

A = (function() {
  function A() {}

  A.prototype.a = function() {
    var b;
    console.log(this);
    b = function() {
      return console.log(this);
    };
    return b();
  };

  return A;

})();

a = new A;

a.a();

Try it yourself at the CoffeeScript website.

This is the most common use of fat arrows in CoffeeScript. This case also includes omnipresent jQuery event handlers, clicks, mousedowns, mouseups, etc.

Fat Arrows with Classes in CoffeeScript

Things get a little tricky in the compiled JavaScript code when we try to apply => on the objects/classes. However, the results are the same in the console with both logs outputting the same object for this:

Fat Arrows with Classes in CoffeeScript
Fat Arrows with Classes in CoffeeScript

The CoffeeScript code:

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

a = new A
a.a()
a.c()

The JavaScript code:

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

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

  A.prototype.a = function() {
    var b;
    console.log(this);
    b = function() {
      return console.log(this);
    };
    return b();
  };

  A.prototype.c = function() {
    return console.log(this);
  };

  return A;

})();

a = new A;

a.a();

a.c();

Try it yourself at the CoffeeScript website.

What is the difference then? Should we just use fat arrows on object methods instead of skinny ones? The matter become clearer if we expand the object in the console, and observe that it has two method c()! One in its prototype and another in the instance:

Fat Arrows Protect Methods
Fat Arrows Protect Methods

The difference is subtle when we invoke the methods, but remember that JavaScript is a prototypal language. If can augment the parent class and all instances that were extended from that class follow the change of prototype. So if we augment A.a() and A.c() methods after we create the a object, the a.a() will be updated while a.c() will stay the same (console.log(@)):

Fat Arrows Method Hasn't Changed
Fat Arrows Method Hasn’t Changed

Fat Arrows with Functions in CoffeeScript

Another usage of fat arrows involves passing of functions to another objects. In this case the -> method loses the reference to the class/object in which it was originally written while the => method keeps track of it even in a foreign context:

Fat Arrows with Functions in CoffeeScript
Fat Arrows with Functions in CoffeeScript

The CoffeeScript code:

class A 
  x: ()->
    console.log(@)
  y: ()=>
    console.log(@)

f = (callback)->  
  callback()

a = new A
a.x()
a.y()
f(a.x)
f(a.y)

The JavaScript code:

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

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

  A.prototype.x = function() {
    return console.log(this);
  };

  A.prototype.y = function() {
    return console.log(this);
  };

  return A;

})();

f = function(callback) {
  return callback();
};

a = new A;

a.x();

a.y();

f(a.x);

f(a.y);

Try it yourself at the CoffeeScript website.

Conclusion about Fat Arrows in CoffeeScript

There’s no reason to be afraid of fat arrows in CoffeeScript. They are time savers (and clarity achievers) when it comes to the nested functions and jQuery event handlers. When they are applied to class methods, the good rule of thumb is: use => when we need @ to be the object in which method is written; use-> when we need @ to be the object in which method is executed.

Author: Azat

Techies, entrepreneur, 20+ years in tech/IT/software/web development expert: NodeJS, JavaScript, MongoDB, Ruby on Rails, PHP, SQL, HTML, CSS. 500 Startups (batch Fall 2011) alumnus. http://azat.co http://github.com/azat-co

4 thoughts on “Understanding Fat Arrows (=>) in CoffeeScript”

  1. Hi Ben,

    I think your explanation is also right. Let me clarify that in my example I used => for y method and it returned the same object in closure while -> method (x) returned window. Therefore, y “remembered” original class/object while x lost it to window.

  2. Hey Azat,
    Do you have the last paragraph backwards?
    “use => when we need @ to be the object in which method is written; use-> when we need @ to be the object in which method is executed.” — I think you mean the other way around? Skinny arrow (no scope override) implicitly scopes to the “object in which the method is written,” but fat arrow (overrides ‘this’) enforces that a function defined inside a class method is scoped to the “object in which method is executed.” Or do I misunderstand your example?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.