Loading...

JavaScript Scope

You can declare variables, write functions, and return values. One more rule decides whether a name is even reachable: scope. Scope answers “from here, which names am I allowed to use?”

What scope means

Scope is the region of your program where a name exists. Outside that region, the same spelling may be invisible — or it may refer to a different binding. Think of rooms: a label taped to the kitchen wall is easy to see in the kitchen; it is not automatically on the street.

Three everyday kinds

📊 Global, function, and block scope

Kind Where the name lives Typical tools Visible where?
global outside every function let / const / var at top level across the script (same page)
function (local) inside a function body parameters and locals only inside that function
block inside { } such as if or a loop let and const only inside that block

These three cover most beginner code. Function locals stay private. Block bindings with let and const stay inside their braces. Globals are shared — useful for a shared counter, risky if every name becomes global.

A global name

javascript
let city = "Tehran";
function showCity() {
console.log(city);
}
showCity();
console.log(city);

Global names sit outside functions

city is declared at the top level, so both the function and the later console.log can read it. Change the string once; every reader sees the new value. Prefer globals only when several parts truly share one value.

A local name inside a function

javascript
function greet() {
let message = "Hello";
console.log(message);
}
greet();
// console.log(message); // Error: message is not defined

Locals stay inside the function

message exists only while greet runs. Outside the function, that name is not defined. Parameters work the same way: they are local to the function that lists them.

Block scope with let

javascript
if (true) {
let score = 10;
console.log(score);
}
// console.log(score); // Error: score is not defined

let and const respect blocks

Inside { }, a let or const binding is visible only in that block. After the closing brace, score is gone. Older var is function-scoped instead — it can “leak” past a block. Prefer let and const so block edges mean what they look like.

Nested code reads outward

javascript
let title = "Shop";
function show() {
let label = "open";
console.log(title + " is " + label);
}
show();

Nested code looks outward

show can read title from the outer scope and label from its own. Lookup walks outward until it finds a match. It does not walk inward: outer code cannot see a name born only inside the function.

Inner name shadows outer

javascript
let status = "ok";
function check() {
let status = "busy";
console.log(status);
}
check();
console.log(status);

Shadowing: the inner name wins inside

Inside check, the local status hides the outer one. The call prints busy. After the function ends, the outer status is still ok. Same spelling, two bindings — scope decides which one you touch.

Show a scoped value on the page

Keep a global label, build a line inside a function that can still read it, and write the result into a paragraph.

Page demo with scope

html
<!DOCTYPE html>
<html>
<head>
<title>scope — page</title>
</head>
<body>
<p id="msg">…</p>
<script>
let place = "Garden";
function line() {
let state = "open";
return place + " is " + state;
}
let box = document.getElementById("msg");
box.textContent = line();
</script>
</body>
</html>

The paragraph shows Garden is open. place is global; state is local to line. The function reads both, returns one string, and the page displays it. Change only place, refresh, and watch the line update. Next lesson covers closures — functions that keep outer names alive after the outer call finishes.

Practice steps

  1. Declare a global let app = "demo" and log it from a small function and from outside.
  2. Put let secret = 1 inside a function; confirm that logging secret outside throws.
  3. Inside an if (true) { } block, declare let n = 5 and log it; try logging n after the block.
  4. From a nested function, read an outer let without redeclaring it.
  5. Shadow an outer let tag = "A" with an inner let tag = "B" and log both places.
  6. In the HTML demo, change only the place string, refresh, and read the paragraph.

Frequent slip-ups

  • Using a local name outside its function — that is a ReferenceError, not a silent blank
  • Expecting var inside a block to stay private the way let does
  • Assuming outer code can see names created only inside a nested function
  • Mixing scope up with return — scope is about visibility; return is about sending a value out
  • Expecting a full closures lesson here — keeping outer names after the call ends is the next page

Summary

  • Scope is where a name can be seen and used
  • Globals live outside functions and are shared across the script
  • Locals and parameters stay inside their function
  • let and const inside { } are block-scoped; prefer them over leaking var
  • Nested code may read outward; outer code cannot see inner-only names
  • An inner binding with the same name shadows the outer one
  • Page updates can combine a global and a local in one returned string
  • Next: closures — functions that remember outer names

🧠 Test Your Knowledge

Ready to Start

Test Your Knowledge

Challenge yourself with this interactive quiz and see how well you understand the topic

❓
8
Questions
🎯
70%
To Pass
♾️
∞
Time
🔄
∞
Attempts

📝 Instructions

  • Read each question carefully
  • Select the best answer for each question
  • You can retake the quiz as many times as you want
  • Your progress will be shown at the top