Skip to content
Plurafy

Scope and Hoisting

Deep dive into JavaScript scope chain and variable hoisting

Predict the output of this code snippet. Why does x have different values in different scopes?

console.log(x); // ?
var x = 5;
if (true) {
var x = 10;
let y = 15;
const z = 20;
}
console.log(x); // ?
console.log(y); // ?

JavaScript has function scope for var and block scope for let/const. Hoisting moves declarations to the top of their scope, but not initializations.

// var is hoisted to function scope
console.log(x); // undefined (hoisted but not initialized)
var x = 5;
if (true) {
var x = 10; // Overwrites the function-scoped x
let y = 15; // Block-scoped
const z = 20; // Block-scoped
}
console.log(x); // 10 (modified inside if block)
console.log(y); // ReferenceError: y is not defined
console.log(z); // ReferenceError: z is not defined
// This code:
console.log(typeof func); // "function"
console.log(typeof func2); // "undefined"
function func() {} // Function declaration is fully hoisted
var func2 = function() {}; // Only var declaration is hoisted
// Is interpreted as:
var func2; // Hoisted declaration
function func() {} // Fully hoisted
console.log(typeof func); // "function"
console.log(typeof func2); // "undefined"
func2 = function() {}; // Assignment happens here
const global = 'global';
function outer() {
const outerVar = 'outer';
function inner() {
const innerVar = 'inner';
console.log(innerVar); // 'inner' - local
console.log(outerVar); // 'outer' - outer scope
console.log(global); // 'global' - global scope
}
return inner;
}
const fn = outer();
fn(); // Prints all three values
// ❌ Avoid: Using var
var x = 5;
if (true) {
var x = 10; // Overwrites outer x
}
// ✅ Good: Use let/const for block scope
let x = 5;
if (true) {
let x = 10; // Creates new block-scoped variable
}
console.log(x); // 5 - outer x unchanged
// ✅ Best: Prefer const, use let when reassignment needed
const API_URL = 'https://api.example.com';
let count = 0;
function example() {
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 5; // let/const create a TDZ before the line they're declared
}
// This is different from var:
function example2() {
console.log(x); // undefined (hoisted)
var x = 5;
}