Understanding Hoisting in JavaScript: The Secrets Behind var, let, and const
Hoisting is a fundamental concept in JavaScript that refers to how variable and function declarations are moved to the top of their containing scope during the compilation phase, before the code execution starts. This behavior can sometimes be tricky to understand, especially when working with different types of variable declarations like var
, let
, and const
. In this blog post, we will break down how hoisting works and why accessing var
before its declaration works differently than accessing let
and const
.
Hoisting with var
: Accessible Before Declaration, but Undefined
In JavaScript, var
declarations are hoisted to the top of their scope, but their initialization (assignment of value) is not. This means that even if you attempt to log the value of a var
variable before it's assigned a value, it will not result in an error, but instead, you’ll see undefined
in the console.
Example:
console.log(myVar); // undefined
var myVar = 10;
console.log(myVar); // 10
What just happened?
The declaration of
myVar
(var myVar
) is hoisted to the top of the code block or function scope. [not really]The value
10
is not assigned tomyVar
until the line wheremyVar = 10;
is encountered.Therefore, when you try to log
myVar
before the assignment, it’s undefined, as the declaration is hoisted but not the assignment.
But what is really happening behind the scenes?
The myVar
variable is already allocated memory during the memory phase in the execution context, even before the code runs, and the memory allocated is set to undefined
. Therefore, when we try to log myVar
before it's declared, we don't get an error; instead, we see undefined
.
Hoisting with let
and const
: The Temporal Dead Zone
While var
behaves a certain way during hoisting, the behavior of let
and const
is different. Both let
and const
are hoisted to the top of their block or global scope just like var
. However, they enter what is known as the Temporal Dead Zone (TDZ) from the start of the block until they are initialized.
If you try to access a let
or const
variable before its declaration, JavaScript will throw a ReferenceError, indicating that the variable is in the Temporal Dead Zone. This is because, although the variables are hoisted, they cannot be accessed until they are initialized.
Example:
console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = 20;
console.log(myConst); // ReferenceError: Cannot access 'myConst' before initialization
const myConst = 30;
What’s happening?
let
andconst
declarations are hoisted, but they don’t get initialized until their respective lines of declaration are executed.Until that happens, any attempt to access them results in a ReferenceError because of the Temporal Dead Zone.
The Temporal Dead Zone ensures that you don’t accidentally access a variable before it has been fully declared and initialized.
The Scope of Variables: Block vs. Global
Even though var
, let
, and const
behave differently during hoisting, they all still exist in their respective scopes — either block scope or global scope.
var
is function-scoped (or globally scoped if declared outside a function).let
andconst
are block-scoped, meaning they are only accessible within the block (e.g., inside curly braces{}
) where they are declared.
Example:
javascriptCopy codeif (true) {
var x = 5; // Function or global scoped
let y = 10; // Block scoped
}
console.log(x); // 5 (accessible)
console.log(y); // ReferenceError: y is not defined (block-scoped)
What’s happening?
The
var
declaration is accessible even outside the block becausevar
is function-scoped or globally scoped.The
let
variable is block-scoped, so it cannot be accessed outside the block in which it is declared.
Why is it called Hoisting?
The term hoisting can be a bit misleading, as it suggests that the variables or functions are literally moved to the top of their scope, which isn't quite what happens under the hood.
The term comes from the way JavaScript behaves during its compilation phase. While the declaration of variables and functions is processed at the top of the execution context (the scope), it's not like the code itself is physically "moved" to the top. Instead, JavaScript prepares an environment where all the variable and function declarations are set up before any code execution begins.
In this setup, the "hoisting" metaphor refers to the process of raising or moving the declarations to the top during the compilation phase, even though the actual code remains in its original order. So, when we talk about hoisting, we are really referring to how the JavaScript engine processes declarations before running the code.
Conclusion: Hoisting and Scoping Rules in a Nutshell
var
: Hoisted to the top, but only the declaration, not the assignment. This means you can access the variable before its declaration, but it will beundefined
until the assignment is executed.let
andconst
: Also hoisted, but they enter the Temporal Dead Zone, meaning you cannot access them before their declaration and initialization. This ensures safer code by preventing premature access.Scope: The scope of
var
is function or global, whilelet
andconst
are block-scoped.
Understanding hoisting and how it affects different variable declarations is crucial for writing clean, bug-free JavaScript code. By recognizing when and where variables are hoisted and how their scopes work, you can avoid common pitfalls and improve the reliability of your code.