Skip to content

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.

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.

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 defined

Function scope isolates variables. Two different functions can both declare const result = ... without interfering with each other — each has its own local result.

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 here

This 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.

When you reference a variable, JavaScript looks for it in a specific order:

  1. Current (innermost) scope
  2. Outer scope
  3. Further outer scopes…
  4. Global scope
  5. ReferenceError if 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.1

The 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.

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()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

The 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.

Functions that read global variables are harder to test and reuse:

// Fragile — depends on a global tourName
function 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 explicit
function 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.

Demonstrate the scope bug, then fix it:

const tourName = 'Cascade Ridge Hike'; // global
// Bug: accidentally reads global instead of a parameter
function logTourBug() {
console.log(tourName); // reads global — works, but fragile
}
logTourBug(); // 'Cascade Ridge Hike'
// Fix: pass the name as a parameter
function 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: let and const declared inside {} — accessible only inside that block. var leaks out; another reason to avoid it.
  • The scope chain: JavaScript searches from the current scope outward to global; ReferenceError if 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.