Skip to content
  • Scope, Scope Chain & Hoisting · JavaScript

Scope, Scope Chain & Hoisting

LearnViaNotes @learnvianotes· 2 min read

Scope decides where a name is visible. JavaScript uses lexical scope: what you can see is fixed by where the code is written, not where it is called.

Kinds of scope

ScopeCreated byHolds
GlobalThe program / scriptGlobals, globalThis properties
ModuleEach ES module fileTop-level declarations of that module (not global!)
FunctionEvery function callParameters, var, inner declarations
Block{ }, if, for, try…let, const, class (and function declarations in strict mode)

The scope chain

When a name is used, the engine looks in the current scope, then the enclosing one, and so on out to global. The first match wins (shadowing); if none matches → ReferenceError.

JavaScript
const level = "global";
function outer() {
  const level = "outer";
  function inner() {
    const extra = "inner-only";
    console.log(level, extra);   // finds outer's `level`
  }
  inner();
}
outer();
try {
  console.log(extra);
} catch (e) {
  console.log(e.name + ": " + e.message);
}
Output
outer inner-only
ReferenceError: extra is not defined

Lexical, not dynamic

JavaScript
const x = "lexical";
function readX() { return x; }
function caller() {
  const x = "dynamic";
  return readX();              // readX sees where it was DEFINED
}
console.log(caller());
Output
lexical

Hoisting summary

DeclarationHoisted?Value before the line runs
function f() {}YesThe full function
var xYesundefined
let / constYes (binding)TDZ → ReferenceError
class C {}Yes (binding)TDZ → ReferenceError
const f = () => {}As a constTDZ
importYesModules are linked before any code runs
JavaScript
console.log(typeof hoisted, typeof notYet);
var notYet = function () {};
function hoisted() {}

var shadow = "global var";
function test() {
  console.log(shadow);   // local var is hoisted → undefined, not "global var"
  var shadow = "local";
}
test();
Output
function undefined
undefined

Accidental globals

In sloppy mode, assigning to an undeclared name silently creates a global. In strict mode (and every ES module) it throws:

JavaScript
try {
  undeclaredTotal = 10;
} catch (e) {
  console.log(e.name + ": " + e.message);
}
Output
ReferenceError: undeclaredTotal is not defined

What is hoisting?

What is lexical scoping?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report