Ad-Hockery

ad-hockery: /ad·hok'@r·ee/, n.
Gratuitous assumptions... which lead to the appearance of semi-intelligent behavior but are in fact entirely arbitrary. Jargon File

CoffeeScript Gotchas: for loops

I was caught out by a subtle difference between JavaScript and CoffeeScript yesterday.

In JavaScript you may be used to iterating over the properties of an object using a for…in loop. For example:

var language = {
    name: 'JavaScript',
    syntaxFamily: 'C'
};

for (prop in language) {
    console.log(prop, language[prop]);
}

The prop variable in the loop is assigned the name of each property in the language object in turn.

When translating some code that uses a for…in loop to CoffeeScript I produced something equivalent to this:

language =
  name: 'CoffeeScript'
  syntaxFamily: 'Ruby'

for prop in language
  console.log "#{prop} '#{language[prop]}"

At first glance that looks equivalent but there’s an important difference lurking. Run it and you’ll see nothing gets logged to the console.

Here’s the generated JavaScript. The problem is pretty obvious:

var language, prop, _i, _len;

language = {
  name: 'CoffeeScript',
  syntaxFamily: 'Ruby'
};

for (_i = 0, _len = language.length; _i < _len; _i++) {
  prop = language[_i];
  console.log("" + prop + " '" + language[prop]);
}

The for…in loop in CoffeeScript assumes iteration with a numeric index; it’s used for iterating over arrays. The correct CoffeeScript syntax is for prop of language - that’s of not in.

Of course, for even more idiomatic CoffeeScript we can have multiple loop variables and in this example it might be appropriate to postfix the loop.

console.log "#{prop} '#{value}" for prop, value of language
Web Statistics