The Secret Life of JavaScript: The Shadow (Hoisting)

The Secret Life of JavaScript: The Shadow (Hoisting)

Understanding the Temporal Dead Zone and the Compile Phase.





Timothy was staring at his monitor, confused. He had written a function at the bottom of his file, called it at the top, and it worked. But when he tried to log a variable the same way, it crashed.

// This works?
sayHello();

// This crashes?
console.log(framework);

function sayHello() {
    console.log("Hello!");
}

let framework = "React";

"It makes no sense," Timothy said. "Does JavaScript read from the top down or not?"

Margaret picked up a piece of chalk. "It does both," she said. "You are confusing the Execution Phase with the Compile Phase."

The Two Passes

Margaret drew a timeline on the board.

"The JavaScript Engine does not just run your code immediately," she explained. "It makes two passes over your file."

  1. Pass 1: Compilation (The Creation Phase). The engine scans for declarations (varletfunctionconst). It allocates memory for them, but it does not assign values.
  2. Pass 2: The Execution Phase. The engine runs the code line by line and assigns values.

"This split creates a phenomenon we call Hoisting," Margaret said. "But different types of variables behave differently during the first pass."

The Function Declaration

Margaret pointed to Timothy's working function.

function sayHello() { ... }

"Function Declarations are special," she said. "During the Compilation Phase, the engine hoists the entire function—the name and the body—into memory."

"So when the Execution Phase starts," Timothy realized, "the tool is already fully built."

"Exactly. You can call it before you define it."

The var Hoist (Function Scope)

Margaret wrote a var example on the board.

console.log(myVar); // undefined
var myVar = 10;

"When the engine sees var," she explained, "it allocates memory and initializes it with undefined immediately. Note that var is hoisted to the top of the Function Scope."

  1. Compilation: "I see myVar. I will save space and set it to undefined."
  2. Execution: The first line runs. It sees undefined. The second line runs, and myVar becomes 10.

"It fails silently," Margaret warned. "It runs, but the data is wrong."

The Temporal Dead Zone (Block Scope)

Then Margaret wrote the modern example using let and const.

{
    console.log(myLet); // ReferenceError!
    let myLet = 20;
}

"This is where let and const differ," she said. "They are Block Scoped (confined to the curly braces {}). They are technically hoisted—the engine knows they exist—but they are uninitialized."

She drew a shaded box on the timeline between the start of the block and the line where the variable is defined.

"This gap is called the Temporal Dead Zone (TDZ)."

"If you try to touch the variable while it is in the Dead Zone," Margaret said, "the engine throws a ReferenceError. It refuses to let you use a variable that hasn't been assigned yet."

The Trap: Function Expressions

Margaret wiped a section of the board. "Here is the trap that catches everyone in interviews. What happens if we use a Function Expression?"

She wrote two examples:

Example A: The const Crash

sayHi(); // ReferenceError! (TDZ)
const sayHi = function() { ... };

Example B: The var Crash

sayHello(); // TypeError: sayHello is not a function
var sayHello = function() { ... };

Timothy looked closely. "Wait. The var version didn't say 'ReferenceError'. It said 'Type Error'."

"Correct," Margaret said. "Because var was hoisted. The engine initialized sayHello as undefined."

"So when I tried to call sayHello()..."

"You were trying to call undefined as a function," Margaret finished. "That is a Type Error. The variable exists, but it is not a function yet."

The Cheat Sheet

Margaret drew a final grid on the board to summarize the rules.

| Type       | Hoisted?  | Initial Value   | Scope    |
| :---       | :---      | :---            | :---     |
| function   | Yes       | The Body        | Block* |
| var        | Yes       | undefined       | Function |
| let/const  | Yes (TDZ) | <uninitialized> | Block    |

* In Strict Mode/Modules

The Conclusion

Timothy looked at his code. He moved his function calls below his definitions.

"Hoisting isn't magic," he said. "It's just memory allocation."

"Correct," Margaret said. "The engine prepares the room before the party starts. If you try to eat the food before it's plated, you will crash."


Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.

Comments

Popular posts from this blog

The New ChatGPT Reason Feature: What It Is and Why You Should Use It

Insight: The Great Minimal OS Showdown—DietPi vs Raspberry Pi OS Lite

Raspberry Pi Connect vs. RealVNC: A Comprehensive Comparison