Pimp my JavaScript, part 2: The biggest gotcha
Every language has its gotchas.
In Ruby, for example, zero and the empty string both evaluate to true in a boolean context. In PHP, several of the built-in functions aren’t functions at all but are really just language features disguised as functions. In Perl, the local statement doesn’t make local variables, but the my statement does. In Objective-C, you can send messages to nil and nothing happens.
Of course, those other languages are a whole different blog post: today’s topic is JavaScript, and what may be its most subtle gotcha.
Consider the following two relatively similar functions. The first is in JavaScript:
function alertLater() {
var local;
for (local = 1; local < 6; local++) {
setTimeout(function () {
console.log(local);
}, local * 1000);
}
}
The second is in Ruby:
def alertLater
threads = []
(1..5).each do |local|
threads << Thread.new do
sleep local
puts local
end
end
threads.each { |thread| thread.join }
end
What is the output from each?
If you guessed the numbers 1 through 5, each on their own line, you’d be only half right. Let’s try the JavaScript version, in this case in Safari’s Web Inspector:

The number 6, five times. Interesting. Let’s try the Ruby version in command-line irb:

The numbers 1 through 5, each on their own line.
Wikipedia explains it pretty well: JavaScript variables have lexical scope, even in closures. That is, the values of variables brought in to an anonymous function by closure in JavaScript are what those variables point to when the function executes, rather than when the function is defined as in most other languages with full support for closures. Even C, the least dynamic language ever, will have dynamic scoping in its new implementation of “blocks”, which are anonymous functions with closures.
In the end, these are simple differences between two different programming languages. Neither is necessarily right or wrong, but it shows that you always have to be aware of what you’re doing, regardless of what language you’re using.