Can you explain hoisting in JavaScript? For example: output of the below code.
Hoisting: declarations are processed before code runs. `var` declarations hoist to function scope, initialized to `undefined`. Function declarations hoist *with* their value. `let`/`const` hoist but stay in the Temporal Dead Zone until the declaration line — accessing them throws ReferenceError. Class declarations are TDZ too.
JS engines do two passes: a compile pass that registers declarations, and an execute pass that runs statements. Hoisting is what we call the visible effect.
var
console.log(x); // undefined (not ReferenceError)
var x = 5;
console.log(x); // 5The declaration var x is hoisted; the assignment stays in place. So x exists everywhere in the function but is undefined until the line runs.
Function declarations
foo(); // "hi" — works
function foo() { console.log("hi"); }The whole function hoists, name and body. Can be called before its source line.
Function expressions don't fully hoist
foo(); // TypeError: foo is not a function
var foo = function () { console.log("hi"); };Only the var foo hoists; the assignment doesn't. foo is undefined at the call.
let / const — Temporal Dead Zone
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 1;The binding exists (so a same-named var doesn't shadow it from an outer scope), but reading it before the let line throws.
Class declarations
new C(); // ReferenceError
class C {}Same TDZ behavior as let.
Function vs var ordering
console.log(typeof a); // "function"
var a = 1;
function a() {}Function declarations hoist after var-declared names but with their value. Then the assignment runs and a becomes 1.
Worked example
function demo() {
console.log(a, b, c); // ?
var a = 1;
let b = 2;
function c() {}
}aisundefined(var hoisted, no value yet).bthrows TDZ ReferenceError.
So the line throws before logging anything.
Modern advice
Use const by default, let when reassignment is needed, never var in new code. Function declarations are fine but be intentional about ordering.
Interview framing
"Declarations are processed before execution. var and function declarations hoist with their identifiers — var is undefined until assignment runs; function declarations are fully usable from the top of their scope. let / const / class hoist into the scope but stay in the Temporal Dead Zone until their declaration line — accessing them throws. So console.log(x); var x = 1 prints undefined; let x throws. The TDZ exists to catch the kind of accidents var silently allowed."
Follow-up questions
- •Why was the TDZ added?
- •What's the difference between function declaration and function expression?
- •How does block scope interact with var?
Common mistakes
- •Assuming let/const are not hoisted at all (they are, into TDZ).
- •Using var and being surprised by shared bindings.
- •Function expression calls before assignment.
Performance considerations
- •No perf impact.
Edge cases
- •Class expressions vs declarations.
- •Function declarations in blocks (legacy / strict mode differences).
- •Hoisting of import statements (whole module).
Real-world examples
- •Codebases that pre-date ES2015; legacy code patterns; interview trick questions.