Output: Hoisting

⭐ Interview Importance: HIGH
⏱️ Revision Time: 4 min

TL;DR

Hoisting output questions test whether you understand the difference between the Creation Phase (where memory is allocated) and the Execution Phase (where code actually runs), and how var, let, and functions behave differently.

Question 1: The Shadowing Trap

var a = 1;

function test() {
  console.log(a);
  var a = 2;
  console.log(a);
}

test();

Output:

undefined
2

Why?
Inside test(), the JavaScript engine spots var a = 2. During the Creation Phase, it hoists the declaration var a to the very top of the test() function scope and initializes it to undefined.
When the first console.log(a) executes, it looks in the local scope, finds the hoisted local a (undefined), and prints it. It completely ignores the global var a = 1 because the local variable shadows it. Then it assigns a = 2, and prints 2.


Question 2: The Temporal Dead Zone (TDZ)

let x = 10;

{
  console.log(x);
  let x = 20;
}

Output:

ReferenceError: Cannot access 'x' before initialization

Why?
Many developers wrongly believe let is not hoisted. It IS hoisted! The block {} creates a new scope. The engine hoists let x to the top of that block. Because it is hoisted locally, console.log(x) does NOT look outside to the global let x = 10. It tries to use the local x.
However, unlike var, hoisted let variables are placed in the Temporal Dead Zone (TDZ) until their actual line of code executes. Accessing it in the TDZ causes a crash.


Question 3: Function vs Variable Priority

console.log(typeof magic);

var magic = "I am a string";

function magic() {
  return "I am a function";
}

console.log(typeof magic);

Output:

"function"
"string"

Why?
During the Creation Phase, Function declarations are hoisted BEFORE variable declarations.

  1. The engine hoists the entire function magic().
  2. It sees var magic. Because the name magic is already registered in memory as a function, the engine ignores the var declaration.
  3. Execution starts. The first console.log sees magic as the function.
  4. The execution hits the line magic = "I am a string". The assignment overwrites the function in memory.
  5. The final console.log sees magic as a string.