Scope answers one question: where can I use this variable? A variable created inside a function or inside a { } block only exists there. Code outside can't see it.
That might sound like a restriction, but it's what keeps large programs manageable. Without scope, every variable in every file would share one space, and two functions that both used a variable called total would overwrite each other. Understanding scope prevents a whole family of "is not defined" errors and leads to one of JavaScript's most useful features, closures.
Global, function and block scope
- Global scope: variables declared outside every function and block. They're visible everywhere.
- Function scope: variables declared inside a function. They're only visible inside that function.
- Block scope:
letandconstdeclared inside any{ }, such as anifor a loop, only exist inside those braces.
Inner code can see outer variables, but outer code can't see inner variables. Keep variables in the smallest scope that works. The fewer places a variable can be changed from, the easier your code is to reason about.
Shadowing
If an inner scope declares a variable with the same name as an outer one, the inner variable shadows, or hides, the outer one inside that scope. It's allowed, but it's confusing to read, so prefer different names.
Why modern code avoids var
var ignores block scope, so a var declared inside an if or a loop leaks out to the whole function. It's also hoisted with the value undefined, so using it too early gives undefined instead of a helpful error. let and const fix both problems, which is why modern code doesn't use var.
Hoisting in brief
Before running your code, JavaScript reads all the declarations in each scope. Function declarations are fully hoisted, so you can call them above the line where they're written. let and const are hoisted too, but they're locked until their line runs. That locked period is called the "temporal dead zone", and using a variable during it throws a clear ReferenceError.
Closures
A function remembers the variables that were around it when it was created, even after the outer function has finished running. That's called a closure:
function makeCounter() {
let count = 0;
return () => ++count;
}
const next = makeCounter();
next(); // 1
next(); // 2count is private. Nothing outside can change it directly, but next can still read and update it. Closures are used for counters, settings that stay private, and event handlers that need to remember a value.
JavaScript Scope Syntax
Scope in brief
const appName = "Pixel"; // global
function demo() {
const inside = "function"; // function scope
if (true) {
const block = "block"; // block scope
}
}JavaScript Scope Summary
- Scope decides where a variable can be used.
- Variables can have global, function or block scope.
- Inner code can see outer variables, but not the other way round.
letandconstrespect block scope;vardoesn't, so avoid it.- A closure is a function that remembers the variables around where it was created.
JavaScript Scope Examples
Each example runs in the page. Edit the code and press Run to see what changes.
Global, function and block
const site = "Codevra";
function showScopes() {
const lesson = "Scope";
if (true) {
const tip = "Use let and const";
console.log(site, "|", lesson, "|", tip);
}
console.log(typeof tip);
}
showScopes();
console.log(typeof lesson);Line-by-line explanation
- Line 1Global, so it's visible everywhere.
- Line 4Function scope, so it's only visible inside
showScopes. - Line 6Block scope, so it only exists inside the
ifbraces. - Line 7Inner code sees all three.
- Line 9Outside the block,
tipdoesn't exist ("undefined" from typeof). - Line 13Outside the function,
lessondoesn't exist either.
var leaks, let doesn't
for (var i = 0; i < 3; i++) {}
console.log("var i after loop:", i);
for (let j = 0; j < 3; j++) {}
console.log("let j after loop:", typeof j);
if (true) {
var leaky = "I escaped!";
let safe = "I stayed inside";
}
console.log(leaky);
console.log(typeof safe);Line-by-line explanation
- Lines 1 to 2
varsurvives the loop, soiis 3 out here. - Lines 4 to 5
letstays inside the loop. - Lines 7 to 10Inside the block: one
var, onelet. - Line 11
varignores the block and leaks out. - Line 12
letrespects the block, sosafedoesn't exist here.
A closure counter
function makeCounter(label) {
let count = 0;
return function () {
count++;
console.log(`${label}: ${count}`);
};
}
const likes = makeCounter("❤️ Likes");
const shares = makeCounter("🔁 Shares");
likes();
likes();
shares();
likes();Line-by-line explanation
- Line 2
countis private to each call ofmakeCounter. - Lines 3 to 6The returned function remembers
countandlabel. That's a closure. - Lines 9 to 10Two independent counters, each with its own
count. - Lines 12 to 15Likes reaches 3 while shares stays at 1.
Common JavaScript Scope Mistakes
Using a block variable outside its block
if (isMember) {
const discount = 0.1;
}
console.log(discount); // ReferenceErrorlet discount = 0;
if (isMember) {
discount = 0.1;
}
console.log(discount);Declare the variable in the scope where you need to use it.
Accidentally creating globals
function setup() {
total = 0; // no let/const: becomes a global by accident
}function setup() {
let total = 0;
}Always declare variables with let or const.
JavaScript Scope in Real Projects
Scope keeps big apps sane
In a large app with hundreds of files, scope stops one part of the code from accidentally overwriting another's variables. Closures power private state, event handlers that remember data, and patterns like debounce that you'll meet in real projects.
JavaScript Scope Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Where can a const declared inside an if block be used?
let and const are block-scoped.What does this print?
let x = "outer";
function test() {
let x = "inner";
console.log(x);
}
test();
console.log(x);x shadows the outer one only inside the function.What does this print?
function make() {
let n = 0;
return () => n += 10;
}
const add = make();
add();
console.log(add());n between calls: 10, then 20.message is used outside the block it was declared in. Fix the code so it logs Status: Open without errors.
const hour = 10;
if (hour >= 9 && hour < 17) {
const message = "Open";
} else {
const message = "Closed";
}
console.log("Status:", message);- Logs "Status: Open"
- No errors
JavaScript Scope Quiz
3 questions to check what you learned.
Which keyword ignores block scope and should be avoided?
- let
- const
- var
- function
What is a closure?
- A function that closes the browser
- A function that remembers variables from the scope where it was created
- A finished loop
- A way to end a program
What happens if you use a
letvariable before its declaration line?- ReferenceError (temporal dead zone)
- It's undefined
- It's 0
- It works normally
JavaScript Scope Challenge
Make a private wallet
Write createWallet(start) that:
- Keeps a private
balancestarting atstart - Returns an object with two functions:
spend(amount)subtracts and returns the new balance,getBalance()returns the balance createWallet(50)→spend(20)returns30, thengetBalance()returns30
function createWallet(start) {
// your code
}
const wallet = createWallet(50);
console.log(wallet.spend(20));
console.log(wallet.getBalance());- spend returns the new balance
- getBalance reflects spending
- Wallets are independent
- balance is private (not a property)