Skip to main content

Lexical scope in JavaScript

What lexical scope is

Lexical scope is the scope determined by where the code is located at the time it is written, not at runtime.

In simpler terms:

Which function has access to which variables is decided at declaration time, not at call time.


Why it's called lexical

The word "lexical" refers to "the text of the program". That is, JS "remembers" the layout of functions and code blocks while parsing, when it reads the source, not when you call the functions.


Example 1: Simple nesting

javascript
let a = 10; function outer() { let b = 20; function inner() { let c = 30; console.log(a, b, c); } inner(); } outer();

Here:

  • inner was declared inside outer.
  • So it has access to the variables of outer and global.

JS remembered the structure at declaration time, not at call time.

The scope chain:

javascript
inner -> outer -> global

Example 2: The difference between "lexical" and "dynamic" scope

Some languages (for example, Bash or old Lisp) use dynamic scope, which is determined by who called the function.

In JavaScript it's lexical: it's determined by where the function is written.

javascript
let x = "global"; function foo() { console.log(x); } function bar() { let x = "local"; foo(); // who called foo? bar, but... } bar();

Result:

javascript
global

Because foo is declared in the global scope, and JS looks for x there, not in the place it was called from (bar).

This is the essence of lexical scope: "look where the function is written, not where it's called".


Example 3: Closures, a practical manifestation of lexical scope

javascript
function makeCounter() { let count = 0; return function() { count++; console.log(count); }; } const counter = makeCounter(); counter(); // 1 counter(); // 2

Here:

  • the inner function remembered the lexical scope of makeCounter
  • and even after it finished running, it still "sees" count.

This is only possible because the scope is lexical, not dynamic.


Visually

javascript
[ Global Scope ] a = 10 ↓ [ outer() Scope ] b = 20 ↓ [ inner() Scope ] c = 30

The function inner always "knows" where to look for a and b, this is determined at declaration time.


Summary

ConceptDescription
Lexical scopeThe scope where a function "sees" variables, determined by its position in the source code
Determined whenWhile writing the code, not at runtime
Why it's neededSo that JS knows which variables are available to each function
Related toLexical Environment, Scope Chain, Closures

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.