One of the best (well, relatively) kept secrets of javascript is the so-called hoisting of variables. This had me confused until I learned about it, as some manifestation are quite fun (except when they generate a mysterious bug that you have to fix, in that case you might as well revise your concept of fun).
Take for example this (voluntarily) crappily written bit of code:
var someCondition = false, myName = "Barbara";
function sayMyName(){
if(someCondition){
var myName = "Oleoblitz";
}
return myName;
}
console.info(sayMyName());
What do you expect the output to be? “Barbara”, right? Since the Oleoblitz line is never executed, being inside the brackets of the if, and the condition is false – and the variable exists in the global scope with the value “Barbara”.
Nah. It outputs “undefined”. This is due to the pleasant little trick called hoisting. Entering the function, the parser looks for all the variable definitions first thing and creates them, with a value of undefined. Well, it’s not exactly the first thing it does, as the arguments passed to the function are examined before of that, but it’s done before any single line inside the function is evaluated.
In the example above, this is what happens: the parser looks at the function, it sees that a var is defined (somewhere! It doesn’t count that the actual line will never be executed – at this stage the parser doesn’t even know if it will be executed or not), so it creates a myName variable with a value of undefined, since this is the default value that variables gets at declaration:
var myName = undefined;
Therefore, it has no reason to look further up the scope (in the globals, in that case) for a myName variable: it’s there already! It’s undefined, well yes, this is not what we meant, but the parser is behaving, really, as per design here – it’s not its fault. The “Oleoblitz” line will never be executed, the var will be returned by the function with its original value of undefined. That’s it.
So, if someone has ever told you to declare all your vars in one go at the beginning of the scope, now you know why: it will prevent hoisting “fun”. It’s true that bugs due to hoisting are relatively rare, but the code is much more readable, and debugging those is no joy, so it’s really a good practice to follow.
Spot the difference:
var someCondition = false, myName = "Barbara";
function sayMyName(){
if(someCondition){
myName = "Oleoblitz";
}
return myName;
}
console.info(sayMyName());
Having removing the “var” inside the function, now everything is hunky-dory: the variable is not redeclared, the line inside the brackets is not executed, the parser looks up the scope for the variable and founds it in the globals. The output is “Barbara”, phew, we are saved.
(Oleoblitz is, according to the legend, a lady from my hometown. Her father lost a bet and was bound to call his first kid with the first word he and his friends saw when stepping outside the osteria).