devnotes.

Scope and the Scope Chain

JavaScript uses lexical (static) scoping — a function's access to variables is determined by where it's written in the code, not by where it's called from.

let outer = "I'm outer";

function outerFn() {
  let inner = "I'm inner";
  function innerFn() {
    console.log(outer, inner); // both accessible
  }
  innerFn();
}
outerFn();

There are three main scope levels: global scope (accessible everywhere), function scope (created by every function call), and block scope (created by {} for let/const, though not for var).

When the engine looks up a variable name and doesn't find it in the current scope, it walks up the scope chain — checking each enclosing scope in order — until it finds a match or reaches the global scope and throws a ReferenceError. This chain is fixed at the time the function is defined, which is exactly what makes closures (the next lesson) possible.