JavaScript Scope
Scope defines where in your code a variable is visible and can be accessed.
What is scope?
Scope is the set of rules that determines where a name (a variable or function) can be referenced in your program. When JavaScript runs, it does not treat every variable as visible everywhere. Instead, each variable belongs to a region of code, and trying to use it outside that region results in an error or an unexpected value. Understanding scope is what lets you reason about which variable a name refers to and why a value is or is not available at a given point.
JavaScript has three main kinds of scope: global scope, function scope, and block scope. The keyword you use to declare a variable, along with where you place the declaration, decides which scope the variable lives in.
- Global scope: declared outside any function or block, visible everywhere in the program.
- Function scope: declared inside a function, visible only within that function.
- Block scope: declared with let or const inside a { } block, visible only within that block.
Block scope with let and const
Variables declared with let and const are confined to the nearest enclosing pair of curly braces. This includes the body of an if statement, a for loop, or a standalone block. Once the block ends, the variable no longer exists. This behavior helps prevent accidental reuse of variable names and keeps temporary values contained.
Block scope in action
<!DOCTYPE html>
<html>
<body>
<h2>Block Scope</h2>
<script>
{
let message = "inside the block";
console.log(message); // "inside the block"
}
// console.log(message); // ReferenceError: message is not defined
if (true) {
const limit = 10;
console.log(limit); // 10
}
// limit is not accessible here
</script>
</body>
</html>Function scope and var
The older var keyword does not respect block boundaries. A var declaration is scoped to the entire function that contains it, regardless of how many blocks it sits inside. This difference is a common source of bugs, which is why modern code favors let and const. The example below shows how var leaks out of a block while let does not.
var vs let inside a block
<!DOCTYPE html>
<html>
<body>
<h2>Function Scope vs Block Scope</h2>
<script>
function testScope() {
if (true) {
var a = 1; // function scoped
let b = 2; // block scoped
}
console.log(a); // 1 -> var leaked out of the if block
// console.log(b); // ReferenceError: b is not defined
}
testScope();
</script>
</body>
</html>Nested scope and the scope chain
Scopes can be nested inside one another. When code looks up a variable, JavaScript first checks the current scope, then the scope that encloses it, and so on outward until it reaches the global scope. This lookup path is called the scope chain. An inner scope can read variables from outer scopes, but outer scopes cannot see variables declared inside inner ones.
Inner scope reading an outer variable
<!DOCTYPE html>
<html>
<body>
<h2>Nested Scope</h2>
<script>
const country = "India";
function greet() {
const name = "Asha";
function inner() {
// both country and name are visible here
console.log(name + " from " + country);
}
inner();
}
greet(); // "Asha from India"
</script>
</body>
</html>Exercise: JavaScript Scope
How is a variable declared with var scoped inside a function?