Hoisting in JS
Before going into the definition of hoisting, let's consider these examples. What do you expect would be the answer to these questions?
Example 1
a = 10;
var a;
console.log(a);
Error? undefined? hmm, no. The output is 10.
What about the below example?
Example 2
console.log(a);
var a = 10;
10, as it would follow the same pattern as example 1? NO. Here a is *undefined*.
Okay, so, now let's understand what is happening.
Hoisting Definition
Hoisting refers to the process whereby all the declarations are moved to the top of the scope before code execution. An important keyword here is "scope", we will understand later in the blog what it signifies.
Going back to the first example, the declaration will move to the top. Example 1 will be handled like below and so we get the output 10.
var a;
a = 10;
console.log(a);
The second example will be handled like below and thus the output is undefined.
var a;
console.log(a);
a = 10;
In hoisting, not only variable declarations are moved to the top but also functions, classes etc.
Example 3
foo();
function foo() {
var a = 10;
console.log(a);
}
It would be handled like:-
function foo() {
var a = 10;
console.log(a);
}
foo();
Example 4
foo();
function foo() {
console.log(a);
var a = 10;
}
The output will be a is undefined. The above example will be handled like this:
function foo() {
var a;
console.log(a);
a = 10;
}
foo();
The a will move to the top of its scope and not the global scope, so we got a as undefined.
Function expression hoisting
Function expressions are not hoisted, only function declarations are:-
foo();
var foo = function bar() {
var a = 10;
console.log(a);
};
The above example would be handled like this:
var foo;
foo();
foo = function bar() {
var a = 10;
console.log(a);
};
We would get a *TypeError* here. The variable foo will be hoisted but not the function bar. The foo would not know of the function bar giving *TypeError.*
Functions are hoisted first
bar(); // Function
var bar;
function bar() {
console.log("Function");
}
bar = function() {
console.log("Variable");
}
It will be handled like:-
function bar() {
console.log("Function");
}
bar();
bar = function() {
console.log("Variable");
}
The *bar* declaration was repetitive so was ignored.
Javascript ES6
The Javascript ES6 introduces keywords let and const. Let's understand how hoisting works for them.
console.log(a);
let a = 10;
If you expected the output to be undefined, you understood the hoisting for var variables, but in this case, it is incorrect. The above throws the error:-
Uncaught ReferenceError: Cannot access 'a' before initializationSo, the
let variables aren't hoisted, no, it's not like that. Variables declared using let and const are hoisted, however, they are not initialized with a default value during hoisting. This means that if you try to access such a variable before it has been initialized in the code, JavaScript will throw a ReferenceError.This is termed a "Temporal Dead Zone", a period between variable creation and its initialization where they can't be accessed.
On the other hand, variables declared with
var are hoisted with a default initialization of undefined. So, if you access them before they are initialised, it gives undefined.