Demystifying Hoisting in JavaScript
Let's dive into some intriguing examples to unravel the mysteries of hoisting.

Today, let's dive into the fascinating world of JavaScript and unravel the mystery behind a concept called hoisting.
You might have come across situations where you can use a function or a variable even before they are declared. Well, that's hoisting for you!
Let's start with a simple example:
console.log(movie); // Output: undefined
console.log(getDirector()); // Output: Christopher Nolan
var movie = "Inception";
function getDirector() {
return "Christopher Nolan";
}
console.log(movie); // Output: Inception
console.log(getDirector()); // Output: Christopher Nolan
In this snippet, we declare a variable movie and a function getDirector but use them before their actual declarations. Surprisingly, JavaScript doesn't throw an error, and we get the expected output.
The Basics of Hoisting
Now, let's explore the concept of hoisting with another example:
console.log("Initial x:", x); // Output: Initial x: undefined
if (true) {
console.log("Inside if, y:", y); // Output: ReferenceError: Cannot access 'y' before initialization
var x = 10;
let y = 20;
console.log("Inside if, x:", x); // Output: Inside if, x: 10
console.log("Inside if, y:", y); // Output: Inside if, y: 20
}
console.log("Outside if, x:", x); // Output: Outside if, x: 10
console.log("Outside if, y:", y); // Output: Uncaught ReferenceError: y is not defined
Here, the output might surprise you.
Let's break down this code and understand the complex interplay of hoisting:
Initial
console.log: We start by logging the initial value ofx. Surprisingly, it printsundefined, showcasing the hoisting mechanism in action.Inside the
ifblock: Here's where it gets interesting. We attempt to log the value ofybefore its declaration. Withvar x = 10;, the variablexis hoisted, but it's initialized toundefinedbefore the assignment. However, when we try to do the same withlet y = 20;, JavaScript throws aReferenceError. Why? Becauseletdeclarations are not hoisted to the entire block; they are only hoisted within the scope they are declared.Logging inside the
ifblock: The subsequent logs demonstrate that despite the attempted log ofycausing an error,xis accessible and holds the value assigned within theifblock.Outside the
ifblock: Moving outside theifblock, we log the values of bothxandy.xretains its value of10due to hoisting, while attempting to accessyresults in aReferenceError.
This is due to hoisting, where variable and function declarations are moved to the top of their containing scope during the compilation phase.
Note: Execution contexts in JavaScript are created when functions are invoked, not for every block of code like
ifstatements.
The complexity arises from the combination of var and let declarations within conditional blocks. While var is hoisted to the entire scope, let is confined to the block in which it is declared.
However, things can get a bit tricky:
console.log("Before declaration - x:", x); // Output: Before declaration - x: undefined
if (true) {
console.log("Inside if - x:", x); // Output: Inside if - x: undefined
var x = 42;
console.log("Inside if, after assignment - x:", x); // Output: Inside if, after assignment - x: 42
}
console.log("Outside if - x:", x); // Output: Outside if - x: 42
console.log("Outside if, before declaration - y:", y); // Output: Outside if, before declaration - y: Uncaught ReferenceError: y is not defined
let y = 10;
console.log("Outside if, after declaration - y:", y); // Output: Outside if, after declaration - y: 10
In this case,
Before declaration of
x: Attempting to log the value ofxbefore its declaration, we getundefined. This showcases the hoisting behavior of variables declared withvar, which are hoisted but initialized toundefined.Inside the
ifblock: Even within the conditional block, attempting to logxbefore its assignment results inundefined. The subsequent log, after the assignmentvar x = 42;, reveals the assigned value, showcasing the distinction between declaration and assignment during hoisting.Outside the
ifblock: Once outside the block, we logxagain, and this time it retains the assigned value of42. The attempt to logybefore its declaration throws aReferenceError, highlighting the different behavior ofletdeclarations.After the declaration of
y: Finally, after declaringywithlet, logging its value now yields the assigned value of10.
The trickiness arises from the interplay between hoisting and the nature of variable declarations in JavaScript:
Undefined with
var: Variables declared withvarare hoisted to the top of their scope but initialized toundefineduntil their actual assignment in the code.Not Defined with
let: Variables declared withletare hoisted but remain in a "temporal dead zone" until their declaration is reached in the code. Attempting to access them before declaration results in aReferenceError.
Hoisting with Functions
Now, let's consider a scenario where we print the function itself:
console.log("Before function declaration - magicFunction:", magicFunction);
// Output: Before function declaration - magicFunction: ƒ magicFunction() {
console.log("Magic in action!");
}
magicFunction();
// Output: Magic in action!
function magicFunction() {
console.log("Magic in action!");
}
console.log("After function declaration - magicFunction:", magicFunction);
// Output: After function declaration - magicFunction: function magicFunction() { console.log("Magic in action!"); }
Let's break down this:
Before function declaration: Attempting to log the function
magicFunctionbefore its declaration, we getthe entire function. This illustrates the hoisting of function declarations, where the function is hoisted to the top of the scope but not yet defined.Function invocation: Surprisingly, invoking
magicFunctionbefore its actual declaration doesn't result in an error. Instead, it gracefully executes the function and logs "Magic in action!".After function declaration: Logging
magicFunctionafter its declaration reveals the full function definition. This showcases JavaScript's unique handling of function hoisting, allowing the function to be accessed before its declaration in the code.
In other languages, this would typically result in an error, but JS handles it gracefully.
Arrow Functions (with var) and Hoisting
Let's throw a curveball with arrow functions (with var declaration):
console.log("Before arrow function declaration - arrowFunction:", arrowFunction);
// Output: Before arrow function declaration - arrowFunction: undefined
arrowFunction();
// Output: Uncaught TypeError: arrowFunction is not a function
var arrowFunction = () => {
console.log("Arrow function magic!");
};
console.log("After arrow function declaration - arrowFunction:", arrowFunction);
// Output: After arrow function declaration - arrowFunction: () => { console.log("Arrow function magic!"); }
Arrow functions, behaving like normal variables, don't support hoisting.
Before arrow function declaration: Attempting to log the arrow function
arrowFunctionbefore its declaration yieldsundefined. This is in stark contrast to function declarations, showcasing the different hoisting behavior of arrow functions.Arrow function invocation: Invoking
arrowFunctionbefore its actual declaration results in aTypeError. Unlike traditional function declarations, arrow functions do not support hoisting in the same way, leading to this runtime error.After arrow function declaration: Logging
arrowFunctionafter its declaration reveals the full function definition. While the variable declaration is hoisted, the arrow function itself is not fully hoisted, and thus, attempting to invoke it before declaration results in an error.
Arrow Functions (with let) and Hoisting
If arrowFunction is declared with let instead of var, the behavior will change due to the differences in how let and var handle hoisting and variable initialization. Here's how the modified code would behave:
console.log("Before arrow function declaration - arrowFunction:", arrowFunction);
// Output: Before arrow function declaration - arrowFunction: Uncaught ReferenceError: Cannot access 'arrowFunction' before initialization
arrowFunction();
// Output: Uncaught TypeError: arrowFunction is not a function
let arrowFunction = () => {
console.log("Arrow function magic!");
};
console.log("After arrow function declaration - arrowFunction:", arrowFunction);
// Output: After arrow function declaration - arrowFunction: () => { console.log("Arrow function magic!"); }
Before arrow function declaration: Attempting to log
arrowFunctionbefore its declaration withletwill result in aReferenceErrorrather thanundefined. This is because variables declared withletare hoisted to the top of their block (or the top of the global scope if declared outside any block), but they are in a "temporal dead zone" until the line of the declaration is reached. Accessing the variable in this zone throws aReferenceError.Arrow function invocation: Invoking
arrowFunctionbefore its actual declaration still results in aTypeError. The behavior is the same as when usingvar.After arrow function declaration: Logging
arrowFunctionafter its declaration will display the full function definition, just as in the previous example.
Function Expressions and Hoisting
Now, let's explore function expressions:
console.log("Before function expression declaration - getReview:", getReview);
// Output: Before function expression declaration - getReview: undefined
getReview();
// Output: Uncaught TypeError: getReview is not a function
var getReview = function () {
console.log("A cinematic masterpiece!");
return "A cinematic masterpiece!";
};
console.log("After function expression declaration - getReview:", getReview);
// Output: After function expression declaration - getReview: function () { console.log("A cinematic masterpiece!"); return "A cinematic masterpiece!"; }
console.log(getReview());
// Output: A cinematic masterpiece!
Surprise! Unlike function declarations, function expressions are not hoisted as-is.
Before function expression declaration: Attempting to log the function expression
getReviewbefore its declaration yieldsundefined. This starkly contrasts with function declarations, emphasizing the unique hoisting behavior of function expressions.Function expression invocation: Invoking
getReviewbefore its declaration results in aTypeError. Unlike function declarations, function expressions are not fully hoisted, leading to this runtime error.After function expression declaration: Logging
getReviewafter its declaration reveals the full function expression definition. The variablegetReviewis hoisted, but the function expression itself is not hoisted as a fully defined function.Function expression invocation after declaration: Invoking
getReviewafter its declaration works as expected, showcasing that the function expression is now fully initialized.
This example solves the puzzle of hoisting and function expressions:
Variable Declaration Hoisted: Similar to variables declared with
var, the declaration of the variablegetReviewis hoisted to the top of the scope.Function Expression Limitation: While the variable is hoisted, the function expression itself is not fully hoisted. Attempting to invoke it before its declaration results in a
TypeError.Temporal Dead Zone: Function expressions have a "temporal dead zone" during which they are not fully initialized, causing runtime errors when accessed before their declaration.
In Summary
Variables are Hoisted with
undefined: Variable declarations get hoisted with an initial value ofundefinedduring the memory creation phase.Function Declarations vs. Expressions: Function declarations are fully hoisted, while function expressions are hoisted but not initialized.
Arrow Functions Play it Cool: Arrow functions don't fully embrace hoisting like traditional function declarations. Arrow functions, behaving like variables, get hoisted and initialized as
undefined.Hoisting is a mechanism in JS where variable and function declarations are moved to the top of their scope before execution.
UNDEFINEDmeans the variable has been declared but not assigned a value, whileNOT DEFINEDmeans the variable is not declared.Mind the Order: The order of declarations matters, especially when using function expressions.
So there you have it, a peek into the magical world of hoisting in JavaScript.
Thank you!




