Block Scope vs Function Scope
Rooms Inside the House
LinkedIn Hook
Quick test: does this print
3orReferenceError?function demo() { for (var i = 0; i < 3; i++) {} console.log(i); } demo();It prints
3. The loop ended, the{ }closed, butvar idoesn't care — it leaked right out of theforblock into the enclosing function scope. Swapvarforletand you'd getReferenceError.This one difference between
varandlet/constexplains half the modern JavaScript style guide. It explains whyfor (let i ...)withsetTimeoutprints0, 1, 2whilefor (var i ...)prints3, 3, 3. It explains why senior engineers tell juniors to "just stop usingvar." And it explains why standalone{ }blocks are suddenly useful.In this lesson you'll learn the difference between function scope and block scope, which keywords respect which boundaries, and how per-iteration bindings make
letplay nicely with closures.Read the full lesson -> [link]
#JavaScript #InterviewPrep #BlockScope #VarLetConst #Frontend #CodingInterview #JSFundamentals
What You'll Learn
- The difference between function scope (
var) and block scope (let/const) - Why
varleaks out ofif,for, and standalone{ }blocks - How per-iteration bindings make
letbehave correctly with closures
Block Scope vs Function Scope — Rooms Inside the House
JavaScript has two primary types of scoping: function scope (created by functions) and block scope (created by {} blocks like if, for, while, and standalone blocks).
Think of function scope like a house — everything inside the house is accessible from any room. Block scope is like individual rooms within that house — what's in a room stays in that room.
Function Scope — var
var is function-scoped. It only respects function boundaries, completely ignoring block boundaries:
function functionScoped() {
if (true) {
var x = "I exist everywhere in this function";
}
for (var i = 0; i < 3; i++) {
// loop body
}
console.log(x); // "I exist everywhere in this function"
console.log(i); // 3 -- leaked out of the for loop!
}
functionScoped();
var variables only get a new scope when they're inside a function:
function outer() {
var a = "outer";
function inner() {
var a = "inner"; // different variable -- new function = new scope
console.log(a); // "inner"
}
inner();
console.log(a); // "outer" -- not affected by inner's `a`
}
outer();
Block Scope — let and const
let and const respect every {} block:
function blockScoped() {
let a = "function level";
if (true) {
let a = "block level"; // different variable -- new block = new scope
const b = "also block level";
console.log(a); // "block level"
console.log(b); // "also block level"
}
console.log(a); // "function level"
// console.log(b); // ReferenceError -- b doesn't exist here
}
blockScoped();
Standalone Blocks
You can create blocks without any control structure — useful for limiting variable scope:
{
const temp = computeExpensiveValue();
// use temp here
console.log(temp);
}
// temp is gone -- clean and contained
// console.log(temp); // ReferenceError
The Practical Difference — Loop Variables
// var: ONE variable shared across all iterations
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log("var:", i), 100);
}
// var: 3, 3, 3
// let: FRESH variable per iteration
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log("let:", i), 100);
}
// let: 0, 1, 2
With let, the JS engine creates a new binding for i in each loop iteration. Each setTimeout callback closes over its own separate i. With var, there's only one i shared by all callbacks.
Comparison Table
| Feature | Function Scope (var) | Block Scope (let/const) |
|---|---|---|
| Created by | function keyword only | Any {} block |
Leaks out of if/for | Yes | No |
| Loop iteration isolation | No (shared variable) | Yes (new variable per iteration) |
| Hoisting behavior | undefined | TDZ |
| Re-declaration in same scope | Allowed | Error |
Common Mistakes
- Using
varinside aforloop with async callbacks and expecting each iteration to have its own counter — you'll get the final value every time. - Treating
{ ... }as a scope boundary forvar— it isn't. Onlyfunctionboundaries containvar. - Re-declaring a
letorconstin the same scope thinking it's harmless — it's aSyntaxError, unlikevarwhich silently allows re-declaration.
Interview Questions
Q: What's the difference between block scope and function scope?
Function scope is created only by the
functionkeyword — variables declared withvarare confined to the nearest enclosing function. Block scope is created by any{ }block (likeif,for, or a standalone block) — variables declared withletorconstare confined to that block.
Q: Why does var in a for loop leak outside the loop?
Because
varis function-scoped, not block-scoped. Theforloop's{}is not a function boundary, sovarignores it. The variable is scoped to the nearest enclosing function (or global scope if there's no function).
Q: Can you create a block scope without an if or for statement?
Yes. A standalone
{ ... }block creates a fresh block scope. Anyletorconstdeclared inside it is not visible outside the braces, which is a clean way to limit the lifetime of temporary variables.
Q: Which keywords create block-scoped variables?
letandconst. Both respect every{ }block, includingif,for,while,switch, and standalone blocks.varignores block boundaries and only respects function boundaries.
Q: Why does for (let i ...) with setTimeout print 0, 1, 2 but for (var i ...) print 3, 3, 3?
With
let, the engine creates a fresh binding forion every iteration, so eachsetTimeoutcallback closes over its own distincti. Withvar, there is a singleishared across all iterations; by the time the callbacks run, the loop has finished andihas its final value.
Quick Reference — Cheat Sheet
BLOCK vs FUNCTION SCOPE -- QUICK MAP
var -> function scope (ignores { } blocks)
let -> block scope (respects { } blocks)
const -> block scope (respects { } blocks, no reassign)
Block boundaries that only let/const respect:
if { }, for { }, while { }, switch { }, { } standalone
Loop iteration bindings:
for (var i ...) -> single shared i
for (let i ...) -> new i per iteration
Re-declaration in same scope:
var -> allowed (silently)
let -> SyntaxError
const -> SyntaxError
Previous: Closures -> The Function That Remembers Next: Module Scope -> Apartments Instead of a Shared Room
This is Lesson 2.4 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.