Yes I can !. What is hoisting and how can one "magically" use variables even before declaration?. Well, its not magic, it is all due to the concept of hoisting. What is hoisting? Let us understand in detail. This blog will be a long detailed explanation of hoisting in different situations. If you like this blog, please leave a thumbs up ! So, Get your coffee, laptop and notebook because we are going to type different codes and see how hoisting works in each one of them!
Let us begin and understand hoisting with one step at a time : For example I need to declare and print a variable. How do I do that?
var x;
x = 5;
console.log(`Your variable x is ${x}`);
Seems good right?. Now when I run this code , I get the output as : "Your variable x is 5".
But what if I change the way I write the above code. I shall make the code like this now :
x=5;
console.log(`Your variable x still is ${x}`);
var x;
I get output again !. But how did this happen? Why did I not get any errors? The phenomena you saw happening is known as hoisting.
Let us define hoisting now. Hoisting is the behaviour of Javascript (and remember not a feature but behaviour) where in Javascript moves all declarations to the top of current scope. So, that means wherever you declare the "x" variable, you can still access the value inside it anywhere in the program - even before its declaration!.
I would like to highlight the work "declaration". Why? Let us see this example.
var x;
console.log(`Your variable x is ${x}`);
x = 5;
Now, I do not get the correct value of x as my answer but instead get "undefined". Crazyy! Isn't it? No, because when I highlighted the word "declaration , I meant to show this. Here I declared the variable and initialized after use but in example 2, I initialized it before use and declared it after use. Hence, only declarations are hoisted and initialisations are not hoisted. How hoisting actually works ? Javascript scans the code for variable declarations before execution and hence we get the value of variable we use -> it is not magically moved above!.
Great going! Now let us understand how hoisting works for variables and functions etc because not everything in Javascript is hoisted. We will also understand their initial value (but what is initial value? - don't worry, it is explained).
1. Function declarations
Here, we are talking about normal functions in Javascript and not the function expressions and arrow functions !. Function declarations are hoisted and their initial value is that of function. Let us see an example
console.log(addNumbers(5, 7));
function addNumbers(i, j) {
return i + j;
}
Output -> 12 Reason -> I am using my function even before declaring it without getting any error -> hence, function declarations are hoisted.
2. The "var" variable
As we saw in the second example, we were able to use the value of var x before declaration. Hence, var variables are hoisted. Initial value -> undefined (if initialization is after usage). How the initial value is undefined ? - See example 3 -> I was able to use "x" but I got the value of "undefined" instead of "5". This is what I mean when I say that "var variables are hoisted but with the initial value of undefined if they are not initialized before declaration".
Example? For sure!
console.log(`My username is ${me}`);
var me = "Joeyouss";
Output -> My username is undefined
Reason -> The variable "me" got hoisted but since it had initialization after usage, it was initialized with the value of undefined because remember "Declarations are hoisted, Initializations are not !" But if I wrote the code like this:
me = "Joeyouss";
console.log(`My username is ${me}`);
var me;
Output -> My username is Joeyouss.
Reason -> I get the correct value of variable "me". Great! But what about variables declared with let and const?
3. Let and const
Variables declared with let and const are not hoisted. I need you to remember this point essentially because a lot of people might think let and const are hoisted too like var but they being a part of modern Js, they are not hoisted! Initial value ? They have initial value of since they fall in TDZ(temporal dead zone). What is TDZ? Check it out in my next upcoming blog! But show us an example! Here you go:
console.log(me);
console.log(blogName);
let me = "joeyouss";
const blogName = "hoisting";
Output -> Uncaught ReferenceError: Cannot access 'me' before initialization
Reason -> I get an error! Because let and const variables are not hoisted so I cannot access them before declaration!. Why this happens ? Because let and const variables remain in TDZ before initialization.
Well done, now the last thing to understand:
4. Hoisting in function expressions and arrow functions
Are they hoisted or not ? Well, it depends on the keyword they are used to declare with. As I told you earlier, variables with let and const are not hoisted while on the other hand, variables with var are hoisted. So: a. if I declare a function expression/arrow function with "var" keyword, they will be hoisted but have an initial value of undefined. b. If I declare a function expression/arrow function with "let" or "const" keyword, they will not be hoisted.
Function expression
Example:
1. With var keyword
console.log(addFuncExp(4, 5));
var addFuncExp = function(i, j) {
return i + j;
};
Output -> Uncaught TypeError: addFuncExp is not a function
Reason -> Yes, my function was hoisted but the output is not 9 as one would expect. Why? Because as I told you above, var has an initial value of undefined hence the function was hoisted but had the value of undefined and we are trying to call undefined in the first line which is not possible !
2. With let keyword
console.log(addFuncExp(4, 5));
let addFuncExp = function(i, j) {
return i + j;
};
Output -> Cannot access 'addFuncExp' before initialization Reason -> let is not hoisted.
3. With const keyword
console.log(addFuncExp(1, 2));
const addFuncExp = function(i, j) {
return i + j;
};
Output -> script.js:2 Uncaught ReferenceError: Cannot access 'addFuncExp' before initialization
Reason-> Const is not hoisted.
Arrow function example:
1. With var
console.log(addArrowFun(3, 4));
var addArrowFun = (i, j) => {
return i + j;
};
Output -> Uncaught TypeError: addFuncExp is not a function Reason -> Hoisted with initial value of undefined.
2. With let
console.log(addArrowFun(3, 5));
let addArrowFun = (i, j) => i + j;
Output-> Cannot access 'addArrowFun' before initialization Reason-> Not hoisted.
3. With const
console.log(addArrowFun(3, 5));
const addArrowFun = (i, j) => i + j;
Output-> Cannot access 'addArrowFun' before initialization Reason-> Not hoisted.
This was it! This was all about hoisting and the concepts underlying the mystery hoisting. I hope this blog was helpful for you, if yes then leave a like or comment. If not, then kindly drop a feedback for improvement. For any doubts , feel free to reach out!.
Have a great day !