Wherefore art thou, Hoisting?
So what’s up with hoisting exactly? Well hoisting is when JavaScript takes your declaration and moves it to the very top. This is what would allow you to use call a function before you’ve actually written the function.
shakespeare(); // Though she be but little, she is fierce.
function shakespeare(){
console.log("Though she be but little, she is fierce.");
}
The code above will go ahead and run the shakespeare function, even though the function is defined below. This is because the defined function is hoisted to the top.
var play = "A Midsummer Night's Dream";
play = "Antony and Cleopatra";
play = "Richard III";
console.log(play); // Richard III
Another effect of hoisting is seen above. When you have one variable defined, and redefined multiple times, JavaScript will assign the last definition it finds.
Perhaps you are wondering why you might assign different definitions to the same variable like that. Let’s take a look at another example.
var backStabber = "Cassius";
function stabCaesar() {
var backStabber = "Brutus";
console.log("Et tu," + backStabber + "?");
}
stabCaesar(); // Et tu, Brutus?
console.log(backStabber); // Cassius
In the above example, we have Cassius as one of Caesar’s assassins. While this is correct, in the play Caesar doesn’t say, “Et tu, Cassius?” So I went into the function and assigned “Brutus” to the backStabber
variable. This way the quote is correct.
But here is where things get interesting. When I log out backStabber
outside of the function, it is still equal to Cassius. I showed you in the example above that if a variable is changed, JavaScript will assign the last definition to the variable. So in this case, it would seem that backStabber
should be equal to Brutus, right?
Well not quite. See what I did differently here was two-fold. First, I put Brutus in the stabCaesar
function. Next, I used var for a second time when I was defining backStabber
. This scopes var backStabber = "Brutus";
to the stabCaesar
function. Because this is a local variable, it doesn’t affect the global backStabber
variable at all.
This would change if I decided not to use var a second time, or if I moved the contents of stabCaesar
outside of the function.
Hoisting can do some tricky things if you don’t know what you are looking for. Some things to remember:
-
Declared variables and functions get hoisted to the top, and are available for use even before they have been technically defined.
-
JavaScript assigns the last definition it finds to a variable that has been defined more than once.
-
Scope can affect the way hoisting plays out if the variable is redefined inside of a function using var.
There are ways to avoid hoisting pitfalls. Namely, be aware of hoisting.
When creating variables in a function, use var to scope them to that function, or leave off var if you are manipulating a global variable that has already been defined. Use unique variable names, and be wary when redefining your variable. This can have unintended consequences.
TL;DR
Hoisting can be confusing, but as long as you are careful in naming your variables, and scoping them to functions properly, you can avoid most issues.