Engrain by ByteRush

JS.02.01 Junior· 9 minCore — asked often

Lexical scope and the scope chain: where JavaScript looks for a variable

A variable is found by where the code is written, not where it is called. Learn global, module, function and block scope, the scope chain and shadowing.

Comes up in: JavaScript, Recruiter screen

Learn#

Ananya’s checkout page shows a total of ₹0 for every cart. The loop clearly adds prices. The bug is one word: she wrote let total again inside the loop, so the loop changed a different total.

A scope is the part of the code where a name can be used. JavaScript has global scope, module scope (the top of a module file), function scope and block scope (anything inside { } for let, const and class).

Each running scope keeps its names in a lexical environment: a table of names and values, plus a link to the scope it was written inside.

To find a name, JavaScript checks the current scope, then follows those links outward until the global scope. That path is the scope chain. Because it follows where code is written, this is called lexical scope.

A name in an inner scope hides the same name outside. That is shadowing — Ananya’s bug.

const city = "Pune";
function outer() {
  const city = "Berlin";
  function inner() {
    const greeting = "Hi";
    console.log(greeting, city);
  }
  inner();
}
outer();
console.log(city);
{ const city = "Delhi"; console.log(city); }
console.log(typeof greeting);

Output (verified)

Hi Berlin
Pune
Delhi
undefined
Looking up city, scope by scopeStep 1 of 4

module scope

  • city = 'Pune'
  • outer

outer scope

    empty

    inner scope

      empty

      The file's top level is the module scope. It holds city = 'Pune' and the function outer.

      Read the steps as text
      1. The file's top level is the module scope. It holds city = 'Pune' and the function outer.
      2. Calling outer creates a new scope. Its own city = 'Berlin' shadows the module's city.
      3. inner runs with greeting = 'Hi'. It looks for city: not here, so it goes one scope out and finds 'Berlin'.
      4. Back at the top level, city is the module's 'Pune'. The inner scopes are gone.

      Predict#

      Predict first

      const x = "global"; function show() { console.log(x); } function caller() { const x = "caller"; show(); } caller(); — what prints?

      Interview angle#

      Say it like this — about 30 seconds

      “JavaScript uses lexical scope: a function can see the variables of the scopes it was written inside, not the scopes it is called from. Each scope has an environment with its names and a link to the outer one. Lookup walks that chain outward to the global scope, and the first match wins — an inner name shadows an outer one. let, const and class are block-scoped; var is function-scoped.”

      Stays on your device. Nothing is uploaded.
      Follow-up What is the difference between lexical and dynamic scope?
      Lexical scope resolves names by where the function is written. Dynamic scope would resolve them by the caller’s variables at run time. JavaScript is lexical; only this behaves dynamically.
      Follow-up Is var block-scoped?
      No. var belongs to the nearest function (or the global scope), so a var inside a block leaks out of it.
      Follow-up What is globalThis?
      One standard name for the global object in every environment — window in pages, self in workers, global in Node.js.

      Practice#

      faded

      Fix cartTotal. Two scope bugs: a shadowed variable and a block-scoped variable used outside its block.

      Done when

      • Two items at ₹100 × 2 and ₹50 × 1 give 250.
      • A 10% discount on that cart gives 225.
      • An empty cart gives 0.
      Your solution
      Ctrl/⌘ + Enter

      Remember#

      Try to answer each card before you open it. Then add them to your reviews.

      What does lexical scope mean?

      A name is resolved by where the code is written, not where it is called.

      How does the scope chain find a variable?

      It checks the current scope, then each outer scope, up to the global scope.

      What is shadowing?

      An inner variable with the same name hides the outer one.

      Which declarations are block-scoped?

      let, const and class (not var).

      Go deeper

      Four layers. Stop at the one your interview needs; each ends with a quick check.

      The core ideaEvery round

      Scopes nest. Code can see its own scope and every scope around it, never the scopes inside it. The nearest name wins.

      Check yourself: Can an outer scope read a variable declared in an inner block?

      No. Lookup only goes outward.

      How it works underneathSenior rounds

      The spec models each scope as an Environment Record with an [[OuterEnv]] link. A function stores the environment where it was created, and each call starts a new record linked to it Source: ECMA-262: Environment Records. Name lookup walks those links — the scope chain.

      Check yourself: What does each environment record link to?

      The environment of the code it was written inside (its outer environment).

      Edge cases and trapsWhere people slip

      In a classic script, top-level var and function declarations become properties of the global object; top-level let and const do not. In modules, nothing at the top level becomes global. globalThis names the global object everywhere Source: MDN: globalThis.

      Check yourself: In a classic script, what does a top-level var create?

      A property on the global object.

      In productionStaff-level answers

      Shadowing bugs are easy to miss in review. Turn on the ESLint rules no-shadow and block-scoped-var, prefer const, and keep functions short so the scope chain stays small. Use modules instead of globals so files cannot overwrite each other’s names.

      Check yourself: Which ESLint rule catches shadowed variables?

      no-shadow.

      Finished the five steps? Mark it, and its cards join your reviews.

      Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

      Interview questions this answers

      • What is lexical scope vs dynamic scope?