Tools
Tools: JavaScript Hoisting and the Temporal Dead Zone — Why var got deprecated, and let/const Rule the Modern Stack
2026-02-14
0 views
admin
Introduction ## What is Hoisting? ## Why var Is Problematic & became deprecated ## Entry of let and const: Block Scope and Predictability ## What Is this Temporal Dead Zone (TDZ)? ## Conclusion In JavaScript, how and when variables become available in our code isn’t always intuitive. Under the hood, the engine’s execution contexts rearranges your declarations before the code runs/executes — this behavior known as hoisting. But not all declarations behave the same. var variables surface early and silently, while modern let and const stay in a so-called Temporal Dead Zone (TDZ) that protects you from subtle bugs.
While learning Javascript, especially while the variables' declations, It was a bit confusing for me to understand what's actually happening under the hood. That's why after some research work, I thought it would be better if I publish a blog on it and express my thoughts on these which will be helpful for others also. Understanding these mechanisms is essential for writing predictable, maintainable code — especially in large applications where improper scoping or premature usage can lead to runtime errors that are difficult to trace. This deep dive will demystify hoisting, explain the motivation for ES6 scoping constructs, and illustrate how TDZ boosts robustness in modern JavaScript. At its core, hoisting is JavaScript’s behavior of logically and conceptually moving declarations — variables and functions' declarations — to the top of their scope during compilation (before code even executes). It is important to note that the code is not physically moved; instead, the JavaScript engine processes the declarations and allocates into memory first (In the memory phase of local/global execution context). Only the declarations are hoisted, not the initializations (assignments of values), and the behavior differs depending on the keyword used (var, let, const). We will come to this later. Here we can see, a exists at the time of print because it was hoisted, but its value wasn’t assigned until the assignment line runs. var variables are function-scoped, not block scoped and hoisted with an automatic initialization to undefined. That means you can reference them before they’re defined — but you won’t get the value you expect.
This behavior can mask logic errors. You might mistakenly assume a variable has been set, only to receive undefined without any warning or exception. This silent failure mode was a frequent source of bugs in pre-ES6 JavaScript, especially in large codebases and loops. In the previous example you can see that the variable is acccessible even before it's declared due to var hoisting which may cause error in different aspect. Other than this var is function-scoped, not even block-scoped. Let's see this with an example. In this example, x is declared within the block of if, so according to that x should not be accessible outside the scope of if. But here due to the use of var within the function-scope x gets hoisted to function-scope. The introduction of let and const in ES6 (2015) fundamentally changed variable semantics:
Both are block-scoped, meaning they only exist within the nearest { … }.
They are hoisted, but they are not initialized at the start of the scope. This is where the Temporal Dead Zone comes into play.
In many articles or youtube videos you might see about saying that let doesn't support hoisting. But in reality, both var, let, const supports hoisting, but in the case of let/const, due to the presence of the concept TDZ, the variables can't be accessible or used before their declarations.
Example: Trying to access x before its declaration throws a ReferenceError, not undefined.
If yoou see the ReferenceError message carefully, then you can notice that it knows when the declaration happened and it's telling us that you can't use it before it's declations. So clearly hoisting is happening here! The Temporal Dead Zone refers to the area of a block where a variable is inaccessible until the moment the computer completely initializes it with a value. Means the variable exists but remains inaccessible until the variable is actually declared and initialized, if you attempt to read or write it, the engine throws an error unlike the var which remains hoisted but undefined. This behavior is intentional: it prevents developers from accidentally using a variable before it’s been initialized, reducing a class of bugs that used to plague code written with var. TDZ Mechanics:
The variable is registered in the memory phase of context during compilation.
Until the declaration line is reached, the variable is uninitialized and inaccessible.
After initialization, it behaves normally within its block. So you can say, Hoisting + no initialization = TDZ Note: Always remember that TDZ is temporal (time-based), not spatial (location-based). I think the following example might help you to understand the Temporal dead Zone. JavaScript’s hoisting behavior is often misunderstood. But remember while all declarations are conceptually hoisted, only var is automatically initialized by undefined and exposed early — a design choice that historically led to silent bugs and unpredictable logic.
ES6’s let and const improve on this by enforcing block-scope and a more disciplined lifecycle through the Temporal Dead Zone. This design forces developers to declare and initialize variables before use, encouraging cleaner, more reliable code.
If you’re writing modern JavaScript — whether in Node.js, frontend frameworks, or full-stack apps — understanding hoisting and TDZ isn’t optional. It’s foundational to avoiding scope-related bugs and optimizing your code for clarity and maintainability. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
console.log(a); // undefined
var a = 5;
console.log(a); // 5 Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
console.log(a); // undefined
var a = 5;
console.log(a); // 5 CODE_BLOCK:
console.log(a); // undefined
var a = 5;
console.log(a); // 5 CODE_BLOCK:
undefined
5 Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
undefined
5 CODE_BLOCK:
undefined
5 CODE_BLOCK:
function example() { if (true) { var x = 5; } console.log(x);
} example(); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
function example() { if (true) { var x = 5; } console.log(x);
} example(); CODE_BLOCK:
function example() { if (true) { var x = 5; } console.log(x);
} example(); CODE_BLOCK:
5 Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10; CODE_BLOCK:
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10; CODE_BLOCK:
{ // TDZ starts here for 'x' console.log(x); // ReferenceError // TDZ continues... // TDZ ends here let x = 10; // 'x' is now initialized console.log(x); // 10
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ // TDZ starts here for 'x' console.log(x); // ReferenceError // TDZ continues... // TDZ ends here let x = 10; // 'x' is now initialized console.log(x); // 10
} CODE_BLOCK:
{ // TDZ starts here for 'x' console.log(x); // ReferenceError // TDZ continues... // TDZ ends here let x = 10; // 'x' is now initialized console.log(x); // 10
}
how-totutorialguidedev.toainodejavascript