Scope
Every variable in JavaScript is accessible only within a certain region of code. That region is its scope. Scope is where bugs quietly hide: a function reads a global variable it should not know about, or a block-scoped variable is accessed outside the block and crashes. Understanding scope prevents an entire category of errors.
Global scope
Section titled “Global scope”A variable declared outside any function or block lives in global scope — accessible everywhere in the file:
const siteName = 'Summit Trail Outfitters'; // global
function logSite() { console.log(siteName); // accessible — global scope}
logSite();Global variables are accessible everywhere, which sounds convenient but creates problems at scale. Any function can read or accidentally overwrite them. For small scripts it is manageable; for large programs it becomes a source of subtle bugs.
Function (local) scope
Section titled “Function (local) scope”Variables declared inside a function are only accessible inside that function. Each call gets its own fresh scope:
function formatTourSummary() { const tourName = 'Cascade Ridge Hike'; // local — only inside this function console.log(tourName);}
formatTourSummary();console.log(tourName); // ReferenceError: tourName is not definedFunction scope isolates variables. Two different functions can both declare const result = ... without interfering with each other — each has its own local result.
Block scope
Section titled “Block scope”let and const are block-scoped: they exist only inside the {} block where they are declared.
if (true) { const blockVar = 'inside the block'; console.log(blockVar); // works}console.log(blockVar); // ReferenceError — blockVar does not exist hereThis applies to if blocks, for loops, while loops, and any other {} block.
var does not respect block scope — it leaks out of if and loop blocks into the enclosing function (or global) scope. This is one of the key reasons to avoid var.
The scope chain
Section titled “The scope chain”When you reference a variable, JavaScript looks for it in a specific order:
- Current (innermost) scope
- Outer scope
- Further outer scopes…
- Global scope
ReferenceErrorif not found anywhere
const tourPrice = 149; // global
function applyDiscount(discount) { // can see: discount (local), tourPrice (global via scope chain) return tourPrice * (1 - discount);}
console.log(applyDiscount(0.1)); // 134.1The function can read tourPrice because the scope chain searches outward until it finds it. However, relying on this — reading global variables inside functions — is fragile. Pass data as a parameter instead.
Closures
Section titled “Closures”A closure is what happens when a function remembers variables from its outer scope even after that outer scope has finished executing:
function makeCounter() { let count = 0; // local to makeCounter return function() { count++; return count; };}
const counter = makeCounter();console.log(counter()); // 1console.log(counter()); // 2console.log(counter()); // 3The inner function closes over count — it keeps a reference to it even after makeCounter has returned. Closures are a natural consequence of scope in JavaScript. You will encounter them in event handlers and callbacks. No need to go deep now — just know the term.
Best practice: parameters over globals
Section titled “Best practice: parameters over globals”Functions that read global variables are harder to test and reuse:
// Fragile — depends on a global tourNamefunction logTour() { console.log(tourName); // which tourName? the global one}If tourName changes elsewhere, the output of logTour changes too — silently.
Functions that receive data as parameters are self-contained:
// Robust — all inputs are explicitfunction logTour(name) { console.log(name);}
logTour('Cascade Ridge Hike');logTour('Summit Loop Trek');This is why the STO helper functions you have been writing — formatPrice(price), isAvailable(available) — accept parameters rather than reading global variables. They work with any data, not just one specific global.
Exercise
Section titled “Exercise”Demonstrate the scope bug, then fix it:
const tourName = 'Cascade Ridge Hike'; // global
// Bug: accidentally reads global instead of a parameterfunction logTourBug() { console.log(tourName); // reads global — works, but fragile}
logTourBug(); // 'Cascade Ridge Hike'
// Fix: pass the name as a parameterfunction logTour(name) { console.log(name);}
logTour('Summit Loop Trek'); // 'Summit Loop Trek'logTour('Valley Floor Walk'); // 'Valley Floor Walk'Then declare const localVar = 'inside' inside an if (true) {} block and try to log it outside the block to observe the ReferenceError.
- Global scope: variables declared outside any function or block — accessible everywhere. Use sparingly.
- Function (local) scope: variables declared inside a function — accessible only inside that function.
- Block scope:
letandconstdeclared inside{}— accessible only inside that block.varleaks out; another reason to avoid it. - The scope chain: JavaScript searches from the current scope outward to global;
ReferenceErrorif not found. - Closures: a function that remembers variables from its outer scope after that scope finishes.
- Best practice: pass data as parameters rather than reading global variables — functions stay portable and predictable.