At HubSpot, I'm fortunate to work with some CoffeeScript experts.  I've picked up a few tricks, most of which aren't mentioned in the docs.

Try Without Catch

One of my first confusions with CoffeeScript was why it always required you to assign the 'catched' error to something, you couldn't have a catch and just drop the error object on the floor. Turns out you can do one better:

try
  thisMightThrowAnError()

butThisDoesntCare()
try {
  thisMightThrowAnError();
} catch (_error) {}

butThisDoesntCare();

Destructuring Arguments

It's common in CoffeeScript, as in Javascript, to pass objects as options to methods. This get's even easier when you use destructing assignment. This is a great way to get the clean binding of positional arguments while maintaining the flexibility of an object.

myMethod = ({size, weight}) ->
  @cost = size * weight
myMethod = function(_arg) {
  var size, weight;
  size = _arg.size, weight = _arg.weight;
  return this.cost = size * weight;
};

You can couple that with the 'this' shorthand:

class Ball
  constructor: ({@size}) ->
Ball = (function() {
  function Ball(_arg) {
    this.size = _arg.size;
  }
  return Ball;
})();

It gets even better when you use the object shorthand notation:

size = 55
new Ball {size}
size = 55;
new Ball({
  size: size
});

The shorthand style is particularly nice when it comes time for you to define module.exports:

module.exports = {start, stop}
module.exports = {
  start: start,
  stop: stop
};

You can even use the shorthand with object properties:

return {@id}
return {id: this.id}

Static Methods

In Javascript, functions are objects, and classes are just functions, meaning you can attach static methods to your classes:

class MyModel

MyModel.get = _.memoize ->
  new MyModel
It turns out that CoffeeScript has a syntax for just this situation:
class MyModel
  @get: _.memoize ->
    new MyModel
MyModel = (function() {
  function MyModel() {}
  MyModel.get = _.memoize(function() {
    return new MyModel;
  });
  return MyModel;
})();

Anonymous Functions

One of the classic bugs folks encounter in Javascript is forgetting that only functions have scope, so anything assigned in a for loop, for example, may have changed when it comes time for callbacks to fire. The do keyword can be used to call a function immediately, passing it it's arguments from the outer scope.

for dog in dogs
  do (dog) ->
    setTimeout ->
      console.log "Dog:", dog
_fn = function(dog) {
  return setTimeout(function() {
    return console.log("Dog:", dog);
  });
};
for (_i = 0, _len = dogs.length; _i < _len; _i++) {
  dog = dogs[_i];
  _fn(dog);
}

You can use the default argument value to create variables which will only live in the inner scope.

do (x=3) -> letsRock(x)(function(x) {
  return letsRock(x);
})(3);

You can also use this trick to call functions as you create them:

do check = ->
  if waitingOn is 0
   done()

setTimeout check, 50
(check = function() {
  if (waitingOn === 0) {
    return done();
  }
})();
setTimeout(check, 50);

Reverse Iteration

Since CoffeeScript 1.5.0 it's been possible to iterate through a list in reverse:

for car in cars by -1
  start(car)for (_i = cars.length - 1; _i >= 0; _i += -1) {
  car = cars[_i];
  start(car);
}

Splats

Most CoffeeScript developers know about splats, but not all know that they can appear anywhere in the argument sequence.

(name, children..., cb) ->var __slice = [].slice;
(function() {
  var cb, children, name, _i;
  name = arguments[0], children = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), cb = arguments[_i++];
});

 

For one of our favorite CoffeeScript tricks, take a look at Mixen.

Recommended Articles

Join our subscribers

Sign up here and we'll keep you updated on the latest in product, UX, and engineering from HubSpot.

Subscribe to the newsletter