JavaScript Fundamentals - Hoisting
March 22, 2016 by
Christoff Truter
JavaScript
One of the basic fundamentals you need to understand when working with JavaScript is a concept called "hoisting", now before I go into the definition, lets have look at some code.
In JavaScript we're allowed to initialize a variable without actually declaring it, like seen in the snippet below.
slimShady = 'the real';
console.log(slimShady);
I generally avoid this practise as it initializes the variable globally, which leads to unnecessary pollution into the global namespace (among other things).
The snippet below will fail with an undefined (Uncaught ReferenceError: slimShady is not defined), since we're attempting to use a variable before we initialized or declared it.
console.log(slimShady);
slimShady = 'the real';
Interestingly, when you slightly alter the snippet, by declaring the variable like seen below, it won't fail but write "undefined" to the console window.
console.log(slimShady);
var slimShady = 'the real';
Now this basically demonstrates what hoisting is all about, the variable declaration gets hoisted to the top of our code, thereby making it available for use
(even before initialization, hence being "undefined" when written to the console).
In the following snippet we demonstrate the extent of the hoisting taking place.
var slimShady = 'the real';
(function() {
console.log (slimShady);
var slimShady = 'i am the real';
}());
Instead of writing the global variable containing "the real" to the console window, we see "undefined" written to the console, giving us another clue to how hoisting works.
If you're unsure, the immediately invoked function expression
(IIFE) has its own lexical scope, we can still access our parent scope, but since we re-declared variable slimShady inside our block, it hoists our declaration to the top of our new lexical scope and creates a shadow version of slimShady
(only available inside our IFFE).
Hoisting also has an influence when creating certain types of functions, in the snippet below we create a shadow function declaration of the standUp function in our IFFE block. Within our IFFE block "yes I'm the real Shady", gets written to the console, while the words "please" will be written outside the IFFE block.
Which in itself isn't hoisting, this is merely part of the pre-compilation-execution phases of JavaScript when using normal function declarations.
function standUp() {
console.log('please');
}
(function() {
standUp();
function standUp() {
console.log("yes I'm the real Shady");
}
}());
standUp();
But what happens when we create our function via function expression instead
(var)?
Just like with the declared variable, the declaration gets hoisted to the top of the IFFE block's lexical scope, but since it drags the declaration to the top of our lexical scope and not the initialization, the code will fail to run, since instead of having a function, we've got an undefined variable
(Uncaught TypeError: standUp is not a function).
function standUp() {
console.log('please');
}
(function() {
standUp();
var standUp = function() {
console.log("yes I'm the real Shady");
}
}());
standUp();
To recap, in JavaScript, hoisting refers to variable declarations being hoisted to the top of their lexical scope.
You will / might have therefore noticed that it is common
(if not best) practise, to declare your variables at the top of your function blocks
(no, its not an old style of coding, its thanks to hoisting).
One final thought, the ES6 spec proposed the let keyword, which provides the developer with a way of declaring unhoisted variables, you can read more about it over
here.