In short
Scope in JavaScript decides where a variable can be used. Learn global, function and block scope, shadowing, and the temporal dead zone in simple words. What does scope mean? Scope is the area of your code where a variable exists and can be used. Think of a school building.
Scope in JavaScript decides where a variable can be used. Learn global, function and block scope, shadowing, and the temporal dead zone in simple words.
What does scope mean?
Scope is the area of your code where a variable exists and can be used. Think of a school building. A notice on the main entrance board (global) is visible to everyone. A notice inside one classroom (local) is only seen by the people in that room. Students inside the classroom can still see the entrance board, but people in the hallway cannot see inside the classroom.
JavaScript has three main kinds of scope:
- Global scope: variables created outside any function or block.
- Function scope: variables created inside a function.
- Block scope: variables created with
letorconstinside curly braces{ }, such as anifor a loop.
Block scope with let and const
A block is any code inside curly braces. Variables made with let and const live only inside the block where you create them.
const temperature = 28;
if (temperature > 25) {
const message = "It's a hot day. Drink water!";
console.log(message);
}
console.log(temperature);
// console.log(message); // ReferenceError: message is not defined
// Output:
// It's a hot day. Drink water!
// 28
message exists only inside the if block. Outside it, JavaScript has never heard of it. temperature was created outside, so it can be used both inside and outside the block. This is the same reason the loop counter i in for (let i = 0; ...) disappears after the loop ends.
Note: The old keyword
varignores block scope, which causes confusing bugs. Modern JavaScript usesletandconst. If you seevarin old tutorials, read it as a warning sign, not an example to copy.
Function scope
Variables created inside a function are local to that function. Each call gets fresh copies, and nothing outside can reach them.
function calculateBill(amount) {
const tipRate = 0.15;
const tip = amount * tipRate;
return amount + tip;
}
console.log(calculateBill(40));
// console.log(tipRate); // ReferenceError: tipRate is not defined
// Output: 46
Parameters like amount are also local. This is a good thing: you can use simple names like total or tip in many functions, and they never clash with each other.
Why global variables cause problems
A global variable can be read and changed from anywhere. That sounds handy, but it causes problems as your code grows:
- Any function can change it by mistake, and it is hard to find which one did.
- Two scripts on the same page might use the same global name and overwrite each other.
- Functions that depend on globals are harder to test and reuse.
let count = 0; // global
function addVisitor() {
count++;
}
function resetForm() {
count = 0; // oops, another function changes the same variable
}
addVisitor();
addVisitor();
resetForm();
console.log(count);
// Output: 0
We expected 2 visitors, but a different function reset the shared variable. The fix is to keep data as local as possible, pass values in as parameters and get results out with return.
Tip: A good rule: create every variable in the smallest scope where it is needed.
What is shadowing?
Shadowing happens when you create a variable inside a block or function with the same name as one outside. The inner one "hides" the outer one inside that area, like a shadow covering it.
const city = "London";
function showTrip() {
const city = "Tokyo";
console.log(`Inside: ${city}`);
}
showTrip();
console.log(`Outside: ${city}`);
// Output:
// Inside: Tokyo
// Outside: London
The two city variables are completely separate. Inside the function, city means "Tokyo". Outside, the original "London" is unchanged. Shadowing is allowed, but it can confuse readers, so use different names when you can.
The temporal dead zone (TDZ), simply explained
With let and const, you cannot use a variable before the line that creates it, even inside the same block. The space between the start of the block and that line is called the temporal dead zone. "Temporal" means "related to time": the variable exists, but it is not ready yet.
{
// console.log(price); // ReferenceError: Cannot access 'price' before initialization
const price = 20;
console.log(price);
}
// Output: 20
Common mistake: Using a variable at the top of your code and creating it further down. With
letandconst, this gives an error instead of a silent bug. The fix is simple: always create variables before you use them.
Practice exercise
Predict what this code prints, then run it to check your answer:
let score = 10;
function play() {
let score = 50;
if (score > 20) {
let score = 99;
console.log("A:", score);
}
console.log("B:", score);
}
play();
console.log("C:", score);
Hint: Each let score creates a new variable in its own block or function. Look at which curly braces each console.log is inside. (Answer: A: 99, B: 50, C: 10.)
Key takeaways
- Scope is the part of your code where a variable can be used.
letandconstare block scoped: they live only inside their curly braces.- Variables inside a function are local and cannot be reached from outside.
- Avoid global variables when you can; pass data with parameters and
return. - Shadowing reuses a name in an inner scope, and the temporal dead zone means you must create a variable before using it.