JavaScript Scope
Understanding variable visibility and accessibility
🔍 What is Scope?
Scope determines where variables can be accessed in your code. Think of it like rooms in a house - some things are visible everywhere, others only in specific rooms!
let globalVar = "I'm visible everywhere!";
function myFunction() {
let localVar = "I'm only visible inside this function!";
console.log(globalVar); // ✅ Can access global
console.log(localVar); // ✅ Can access local
}
myFunction();
console.log(globalVar); // ✅ Can access global
// console.log(localVar); // ❌ Error! Can't access local
Console Output:
I'm only visible inside this function!
I'm visible everywhere!
Types of Scope
Global Scope
Accessible everywhere
var globalVar = "Global";
// Accessible anywhere
Function Scope
Only inside functions
function test() {
var funcVar = "Function";
// Only inside this function
}
Block Scope
Inside { } blocks
if (true) {
let blockVar = "Block";
// Only inside this block
}
Lexical Scope
Nested function access
function outer() {
let x = 1;
function inner() {
console.log(x); // Can access x
}
}
🔹 Global vs Local Scope
Understanding the difference between global and local variables:
// Global scope - accessible everywhere
let userName = "Alice";
let userAge = 25;
function displayUserInfo() {
// Local scope - only accessible inside this function
let greeting = "Hello";
let message = `${greeting}, ${userName}! You are ${userAge} years old.`;
console.log(message);
console.log("Local greeting:", greeting);
}
function anotherFunction() {
console.log("Can access global userName:", userName);
// console.log(greeting); // ❌ Error! greeting is not accessible here
}
displayUserInfo();
anotherFunction();
console.log("Global userName:", userName);
Console Output:
Local greeting: Hello
Can access global userName: Alice
Global userName: Alice
🔹 Block Scope with let and const
let and const have block scope, var has function scope:
function scopeDemo() {
console.log("=== Block Scope Demo ===");
if (true) {
var varVariable = "I'm var - function scoped";
let letVariable = "I'm let - block scoped";
const constVariable = "I'm const - block scoped";
console.log("Inside block:");
console.log(varVariable); // ✅ Works
console.log(letVariable); // ✅ Works
console.log(constVariable); // ✅ Works
}
console.log("Outside block:");
console.log(varVariable); // ✅ Works - var is function scoped
// console.log(letVariable); // ❌ Error - let is block scoped
// console.log(constVariable); // ❌ Error - const is block scoped
}
scopeDemo();
Console Output:
Inside block:
I'm var - function scoped
I'm let - block scoped
I'm const - block scoped
Outside block:
I'm var - function scoped
🔹 Lexical Scope (Closures)
Inner functions can access outer function variables:
// Lexical scope example
function outerFunction(x) {
console.log("Outer function called with:", x);
// This variable is in the outer function's scope
let outerVariable = `Outer: ${x}`;
function innerFunction(y) {
// Inner function can access outer function's variables
let innerVariable = `Inner: ${y}`;
console.log("From inner function:");
console.log("- Can access outerVariable:", outerVariable);
console.log("- Can access parameter x:", x);
console.log("- Own variable:", innerVariable);
return `${outerVariable} + ${innerVariable}`;
}
// Return the inner function
return innerFunction;
}
// Create a closure
let myClosure = outerFunction("Hello");
let result = myClosure("World");
console.log("Final result:", result);
Console Output:
From inner function:
- Can access outerVariable: Outer: Hello
- Can access parameter x: Hello
- Own variable: Inner: World
Final result: Outer: Hello + Inner: World
🔹 Scope Chain
JavaScript looks for variables from inner to outer scope:
// Scope chain demonstration
let level1 = "Global level";
function levelOne() {
let level2 = "Function level";
function levelTwo() {
let level3 = "Nested function level";
function levelThree() {
let level4 = "Deep nested level";
// JavaScript searches in this order:
// 1. Current scope (level4)
// 2. Parent scope (level3)
// 3. Grandparent scope (level2)
// 4. Great-grandparent scope (level1)
console.log("From deepest level:");
console.log("Level 4:", level4); // Found in current scope
console.log("Level 3:", level3); // Found in parent scope
console.log("Level 2:", level2); // Found in grandparent scope
console.log("Level 1:", level1); // Found in global scope
}
levelThree();
}
levelTwo();
}
levelOne();
Console Output:
Level 4: Deep nested level
Level 3: Nested function level
Level 2: Function level
Level 1: Global level
🔹 Common Scope Pitfalls
Avoid these common scope-related mistakes:
// Pitfall 1: Loop variable scope with var
console.log("=== Loop Variable Pitfall ===");
// Problem with var
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log("var i:", i); // Always prints 3!
}, 100);
}
// Solution with let
for (let j = 0; j < 3; j++) {
setTimeout(() => {
console.log("let j:", j); // Prints 0, 1, 2
}, 200);
}
// Pitfall 2: Accidental global variables
function createAccidentalGlobal() {
// Forgot to declare with let/const/var
accidentalGlobal = "Oops, I'm global!";
}
createAccidentalGlobal();
console.log("Accidental global:", accidentalGlobal); // Works but bad practice!
Console Output:
Accidental global: Oops, I'm global!
var i: 3
var i: 3
var i: 3
let j: 0
let j: 1
let j: 2
🔹 Best Practices
Scope Best Practices:
- Use let/const: Prefer block-scoped variables over var
- Minimize globals: Keep global variables to a minimum
- Declare variables: Always use let, const, or var
- Use meaningful names: Avoid variable name conflicts
- Keep scope small: Declare variables as close to usage as possible