Demystifying JavaScript Hoisting: How var, let & const Behave
1. What is JavaScript Hoisting?
Hoisting refers to JavaScript's default behavior of moving declarations (not initializations) to the top of the scope before code execution. Essentially, when the code runs, variable and function declarations are processed first, which is why you can sometimes use a variable or function before it is declared in the code.
However, only declarations are hoisted, not the initializations.
For example:
console.log(myVar); // undefined
var myVar = 5;
Even though myVar
is declared after the console.log
, JavaScript hoists the declaration to the top. The code is interpreted as:
var myVar;
console.log(myVar); // undefined
myVar = 5;
In this example, the variable myVar
is hoisted but remains undefined until the line where it is initialized.
2. How Does Hoisting Affect var
, let
, and const
?
Hoisting behaves differently for variables declared with var
, let
, and const
. Here's how:
var
Hoisting
Variables declared with var
are hoisted to the top of their scope (either global or function scope). However, they are initialized with undefined
until the line where they are explicitly assigned a value.
Example:
console.log(hoistedVar); // undefined
var hoistedVar = 10;
console.log(hoistedVar); // 10
In this case, the var
declaration is hoisted, but the initialization (hoistedVar = 10
) is not, so the first console.log
returns undefined
.
let
and const
Hoisting
Variables declared with let
and const
are also hoisted, but they are not initialized. These variables exist in a "temporal dead zone" (TDZ) from the start of the block until the declaration is encountered. Accessing them before their declaration results in a ReferenceError
.
Example:
console.log(hoistedLet); // ReferenceError: Cannot access 'hoistedLet' before initialization
let hoistedLet = 20;
The key difference here is that accessing a let
or const
variable before it’s declared results in an error, rather than undefined
.
Comparison Table: var
vs let
vs const
Hoisting
Variable Type | Hoisted | Default Initialization | Temporal Dead Zone | Can be Redeclared |
var | Yes | undefined | No | Yes |
let | Yes | No | Yes | No |
const | Yes | No | Yes | No |
3. Function Hoisting Explained
Functions in JavaScript are hoisted differently depending on whether they are declared as function declarations or function expressions.
Function Declarations
A function declaration is fully hoisted. This means the entire function (including its body) is hoisted to the top of its scope, allowing you to invoke the function before its declaration in the code.
Example:
console.log(add(5, 10)); // 15
function add(a, b) {
return a + b;
}
The function declaration add
is hoisted to the top, so the call to add(5, 10)
works even before the function is declared.
Function Expressions
Function expressions, whether assigned to var
, let
, or const
, are only partially hoisted. The variable that holds the function is hoisted, but the function definition itself is not.
Example:
console.log(subtract(10, 5)); // TypeError: subtract is not a function
var subtract = function(a, b) {
return a - b;
};
In this case, the var subtract
declaration is hoisted, but the assignment (function(a, b) { ... }
) is not, which results in a TypeError
.
4. Common Pitfalls with Hoisting
Accessing Variables Before Declaration (let
and const
)
As explained earlier, accessing variables declared with let
or const
before their declaration will throw a ReferenceError
due to the temporal dead zone.
Example:
console.log(myConst); // ReferenceError
const myConst = 100;
Variable Overwriting with var
Since var
allows redeclarations, it can lead to unexpected results:
var message = "Hello";
var message = "World"; // No error
console.log(message); // "World"
To avoid such issues, prefer using let
or const
.
Function Hoisting Confusion
Beginners often get confused between function declarations and expressions. For instance:
console.log(greet()); // TypeError: greet is not a function
var greet = function() {
return "Hello!";
};
Because greet
is a function expression, only the var greet
is hoisted, not the function body.
5. Best Practices for Avoiding Hoisting Issues
Always Declare Variables at the Top: To avoid confusion and potential errors, always declare your variables and functions at the top of their respective scope.
let count = 0; const max = 100;
Use
let
andconst
Instead ofvar
: Sincelet
andconst
provide block-level scoping and prevent redeclarations, they are generally a safer option.Understand Temporal Dead Zones: Be mindful of the temporal dead zone when using
let
andconst
and avoid accessing these variables before their declarations.Be Aware of Function Expressions: Know when you’re dealing with a function declaration vs. a function expression. If you need the function to be hoisted, use a declaration.
6. Hands-On Coding Exercises
Exercise 1: Hoisting Behavior of var
, let
, and const
Test the behavior of var
, let
, and const
in this code snippet:
console.log(myVar); // undefined
var myVar = 1;
console.log(myLet); // ReferenceError
let myLet = 2;
console.log(myConst); // ReferenceError
const myConst = 3;
Exercise 2: Function Declaration vs. Function Expression
Write the following code and explain the results:
console.log(declaredFunc()); // "I am declared"
console.log(exprFunc()); // TypeError: exprFunc is not a function
function declaredFunc() {
return "I am declared";
}
var exprFunc = function() {
return "I am an expression";
};
7. Conclusion: Mastering Hoisting in JavaScript
Understanding how hoisting works in JavaScript is critical to avoiding errors and writing predictable code. Whether you're working with var
, let
, const
, or functions, knowing how they behave under hoisting helps you avoid common pitfalls. Remember to always declare your variables at the top of the scope and use let
and const
to reduce the risk of hoisting-related bugs.
Subscribe to my newsletter
Read articles from Piyush kant directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by