Where a Variable Is Visible
JavaScript Scope
Scope determines who can see a variable. JavaScript has block, function, module, and global scope.
What you'll learn
- Distinguish block, function, and module scope
- Understand how nested scopes look up names
- Know why variables in inner scopes can shadow outer ones
Scope is the region of code where a variable is accessible. JavaScript has four kinds:
| Scope | Where |
|---|---|
| Block | Inside { } — if, for, plain blocks |
| Function | Inside the function body |
| Module | Inside a module file |
| Global | Outside everything |
Block Scope
let and const are block-scoped — they only exist inside the
nearest enclosing { }.
if (true) {
const message = "inside";
console.log(message); // "inside"
}
// console.log(message); // ReferenceError — not defined here Function Scope
Every function creates its own scope. Variables declared inside aren’t visible outside.
function counter() {
const start = 0;
let n = start;
n++;
return n;
}
console.log(counter()); // 1
// console.log(start); // ReferenceError
// console.log(n); // ReferenceError Nested Scopes Look Outward
Inner scopes can read names from outer scopes. This is called lexical scope — what’s accessible depends on where the code is written, not who calls it.
const outer = "I'm outside";
function inner() {
console.log(outer); // ✅ can see outer
const x = "I'm inside";
console.log(x);
}
inner();
// console.log(x); // ❌ ReferenceError The chain goes from innermost outward: block → function → module → global. JavaScript stops at the first scope that has the name.
Shadowing
If an inner scope declares the same name, it shadows the outer one. The inner declaration takes precedence within its scope.
const x = "outer";
function show() {
const x = "inner"; // shadows the outer x
console.log(x); // "inner"
}
show();
console.log(x); // "outer" Module Scope
Files imported with import (or marked type="module") have their
own scope. Top-level let/const/function/class are visible
only inside that file — unless you export them.
We’ll dig into modules in Section 6.
Global Scope
Variables declared at the very top of a non-module script become
global. In the browser, that means window.X. In Node, globalThis.X.
var and Function Scope (Legacy)
var is function-scoped, not block-scoped. Declarations inside a
block leak out:
function test() {
if (true) {
var leaky = "I leak";
let trapped = "I don't";
}
console.log(leaky); // "I leak" — survives outside the if!
// console.log(trapped); // ReferenceError
}
test(); This is one of the main reasons let and const exist. Don’t write
var in new code.
Up Next
A surprising consequence of function scope plus inner functions — closures.
JavaScript Closures →