hoisting javascript variables
The other day I encountered something that I found a little bit surprising about the way JavaScript variables are bound in closures.
Take a look at this code:
I know… it’s ugly. Why would you confuse yourself with something like this?
In this case: to prove a point. Can you guess the output?
The actual output of this script is:
If you’re like me, that might be surprising. A week ago I would have thought that it was:
But, I’ve been reading David Flanagan’s “Definitive Guide” to JavaScript, and I was a little surprised to read about “hoisting” of variables in JavaScript. I’ve been developing JS applications for years but somehow managed to avoid encountering this.
What is the reason?
Even though we often declare variables close to where they are used, JavaScript will take our declarations and “hoist” them up to the top of the current scope before executing any code in the enclosing block.
That’s why the output is 2 1
in the example above. The second var x
is “hoisted” to the top of the test()
function, so the assignment of x = 2
is made in the context of the variable x
that is enclosed in the scope of test()
, and not the x
that is defined in the global scope.
That means that the assignment of x = 2
occurs before the declaration!
This seems a little nutty, but this applies to both variables and functions. It is kind of nice to be able to put function declarations at the end of a closure, and put their use in front of their definitions.
Why does it matter?
I’ve probably not seen this because it’s unlikely that we’d want to use a global variable in one statement, and then declare a local variable of the same name shortly afterward.
However, it’s not entirely unlikely that you might have something like this happen unintentionally in a real world application.
For example, imagine a case where the distance from your declaration in the closure scope and the initial declaration in the enclosing scope is 30 lines of code. Your eye might not be so quick to see the re-use of variable name, especially if it’s something like temp
.
I wouldn’t recommend writing code to intentionally utilize this feature of JavaScript, but I hope that knowing this might help you become a better debugger.