Global vs function vs block scope
By FrontendPro Editorial Team Updated 9/26/2026
Answer
The three levels differ in how wide a variable's visibility is, and which one you get is decided by the keyword you declare it with.
| Scope | Created by | var | let / const |
|---|---|---|---|
| Global | Outside everything | Yes, and attaches to window | Yes, but not on window |
| Function | Any function body | Yes | Yes |
| Block | Any { } | No | Yes |
The row that causes bugs is the last one. var ignores blocks entirely:
function demo() {
if (true) {
var a = "var";
let b = "let";
}
console.log(a); // "var" — escaped the block
console.log(b); // ReferenceError
}
Why each level is risky in its own way
Global is the one to avoid. Anything can overwrite it, two scripts can collide on the same name, and var at the top level in a browser becomes a property of window. Modules fix this: top-level declarations in an ES module are scoped to that module, not to the page.
Function scope is fine, but with var it means a variable declared deep inside a branch is visible across the entire function — often far from where it makes sense.
Block scope is the one you usually want. It keeps a variable alive exactly as long as it is relevant, and it is what makes loops behave:
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); // 3, 3, 3
for (let i = 0; i < 3; i++) setTimeout(() => console.log(i)); // 0, 1, 2
let gives each iteration its own binding; var gives all three callbacks the same one.
The practical rule
Use const by default, let when reassignment is genuinely needed, and var never. Declare each variable in the narrowest block that still works — narrow scope means fewer places to check when something goes wrong.
