What is lexical scoping?

JavaScript

The short answer

Lexical scoping means that a function's access to variables is determined by where the function is written in the code, not where it is called. The word "lexical" refers to the position of code in the source text. If a function is written inside another function, it has access to the outer function's variables — no matter where or when the inner function runs.

How it works

Let me show you a simple example:

function outer() {
const message = 'Hello';
function inner() {
console.log(message);
}
inner();
}
outer(); // "Hello"

The inner function can access message because it is written inside outer. JavaScript determined this access at the time the code was written (at "lex" time), not at runtime.

Now look at this:

const message = 'Global';
function outer() {
const message = 'Outer';
function inner() {
console.log(message);
}
return inner;
}
const fn = outer();
fn(); // "Outer", not "Global"

Even though fn() is called in the global scope, it still prints "Outer". That is because inner was defined inside outer, so it looks at outer's scope for variables — not the scope where it is called. This is lexical scoping.

Lexical scope vs dynamic scope

Some programming languages use dynamic scoping, where a function looks at the scope of the function that called it (the call site). JavaScript does not do this. JavaScript uses lexical scoping.

const name = 'Global';
function sayName() {
console.log(name);
}
function wrapper() {
const name = 'Wrapper';
sayName();
}
wrapper(); // "Global"

If JavaScript used dynamic scoping, this would print "Wrapper" because sayName was called from inside wrapper. But JavaScript uses lexical scoping, so sayName looks at where it was defined — the global scope — and finds name as "Global".

The scope chain

When JavaScript looks for a variable, it follows a chain:

  1. First, it checks the current function's own scope
  2. If not found, it checks the outer function's scope
  3. If still not found, it checks the next outer scope
  4. This continues until it reaches the global scope
  5. If not found anywhere, it throws a ReferenceError
const a = 'global';
function first() {
const b = 'first';
function second() {
const c = 'second';
function third() {
console.log(a); // "global" — found in global scope
console.log(b); // "first" — found in first's scope
console.log(c); // "second" — found in second's scope
}
third();
}
second();
}
first();

The third function can access variables from second, first, and the global scope because it is nested inside all of them. This scope chain is determined by the lexical structure of the code.

Why this matters for closures

Lexical scoping is the reason closures work. A closure is what happens when a function keeps access to its lexical scope even after the outer function has finished running.

function makeGreeter(greeting) {
return function (name) {
console.log(`${greeting}, ${name}`);
};
}
const hello = makeGreeter('Hello');
hello('John'); // "Hello, John"

The returned function remembers greeting because of lexical scoping. It was defined in a scope where greeting existed, so it will always have access to it.

Interview Tip

When the interviewer asks about lexical scoping, the key point they want to hear is that scope is determined by where functions are written, not where they are called. Use a simple example where you return a function and call it from a different scope to prove the point. If you can connect lexical scoping to closures, that shows even deeper understanding.

Why interviewers ask this

Lexical scoping is the foundation of how variables work in JavaScript. It determines what a function can see and access. Understanding it is essential for understanding closures, the scope chain, and common bugs with variable access. When interviewers ask about this, they want to see if you know how JavaScript resolves variables and if you can predict the output of nested function examples.