Lexical Scope in JavaScript: A Simple and Easy Guide
Sep 04, 2026 5 Min Read 2731 Views
(Last Updated)
Ever declared a variable, used it a few functions deep, and gotten a confusing “not defined” error even though you swore you declared it? That confusion almost always traces back to one concept: lexical scope.
Lexical scope in JavaScript means a variable’s accessibility is determined by where it’s physically written in your code, not by how or where a function gets called.
JavaScript decides which variables a function can access by looking at the code’s structure at write-time, which is exactly why the language stays predictable and debuggable even as programs grow large.
This guide breaks down Lexical Scope in JavaScript in plain language: what it actually means, how it works, how it powers closures, and where beginners most often get confused.
Table of contents
- TL;DR Summary
- Understanding Scope Before Lexical Scope
- What Is Scope?
- Scopes in JavaScript
- Scopes in JavaScript at a Glance
- What Is Lexical Scope in JavaScript?
- Lexical Scope in JavaScript vs Dynamic Scope
- Why Lexical Scope Is Predictable
- Nested Functions and Lexical Scope in JavaScript
- Invalid Access Example
- Lexical Environment and the Scope Chain in JavaScript
- Lexical Scope and Closures
- Lexical Scope with var, let, and const
- var and Lexical Scope
- let and const
- Common Lexical Scope Confusions
- Confusion 1: Function Call vs Function Definition
- Confusion 2: Shadowing Variables
- Arrow Functions and Lexical Scope
- Real-World Importance of Lexical Scope
- Wrapping it up
- FAQs
- 1) Is Block Scope the Same as Lexical Scope?
- 2) Does Var Follow Lexical Scope?
- 3) Do Arrow Functions Follow Lexical Scope?
- 4) What Is The Importance Of Lexical Scope In JavaScript?
TL;DR Summary
- What it is: a variable’s accessibility depends on where it’s written in the code, fixed at write-time, not at the moment a function runs
- The three scope types: global, function, and block, each with different rules for what’s visible where
- Why it matters: Lexical Scope in JavaScript is the entire mechanism behind closures, and it’s one of the most commonly tested interview concepts
- The opposite approach: dynamic scope (used by some other languages) determines scope based on how a function is called, not where it’s written, unlike Lexical Scope in JavaScript
- Where beginners trip up: confusing function definition location with function call location, and accidentally shadowing variables
Understanding Scope Before Lexical Scope
Before getting into Lexical Scope in JavaScript specifically, it helps to understand what “scope” means in general terms first.
What Is Scope?
Scope determines where in your code a variable or function can actually be accessed. In short, scope answers questions like:
- Where can I use this variable?
- Where does this function actually exist?
- Why can’t JavaScript find a variable I know I declared?
In JavaScript, scope exists to keep variables from colliding with each other. It’s also the general idea Lexical Scope in JavaScript builds on directly, keeping your code organized and safe from accidental overwrites.
Also read: A Comprehensive Guide On Objects, Methods, and Classes In JavaScript
Scopes in JavaScript

Scopes in JavaScript at a Glance
| Scope Type | Where Variables Are Visible | Declared With |
|---|---|---|
| Global | Everywhere in your code | Any declaration outside functions/blocks |
| Function | Only inside the function where it’s declared | var, let, or const inside a function |
| Block | Only inside the specific { } block where it’s declared | let or const inside an if, for, or similar block |
1. Global Scope
Variables declared outside all functions or blocks belong to the global scope.
let siteName = "GUVI";
function showSite() {
console.log(siteName);
}
showSite();
siteNameis accessible everywhere in the file- Overusing global variables invites bugs, since anything can modify them
- Keep global scope usage minimal
2. Function Scope
Variables declared inside a function can’t be accessed from outside that function.
function calculate() {
let total = 100;
console.log(total);
}
calculate();
// console.log(total); // ReferenceError
This isolation prevents accidental overwrites and keeps your code safer overall.
Also read: 45 JavaScript Questions Towards Better Interviews
3. Block Scope
Variables declared with let or const inside a block (like an if statement) are only visible within that block.
if (true) {
let score = 90;
console.log(score);
}
// console.log(score); // Error
Block scope is a big part of why modern JavaScript is easier to predict and debug than older var-based code.
Also read: From Tutorials To Real Code: Building While You Learn JavaScript
What Is Lexical Scope in JavaScript?
Lexical scope in JavaScript refers to the rule that a variable’s accessibility is determined by where it is written in the source code.
In simpler words:
JavaScript uses the code structure to determine the variable scope, and not the execution of functions.
This means:
- Scope is fixed at the time of writing the code
- Functions remember their surrounding environment
- The scope does not change dynamically
Also read: Best JavaScript Roadmap Beginners Should Follow
Lexical Scope in JavaScript vs Dynamic Scope
This distinction comes up constantly in interviews, and it’s worth understanding clearly rather than just memorizing the term “lexical.”
| Aspect | Lexical (Static) Scope | Dynamic Scope |
|---|---|---|
| Determined by | Where the code is written | How the function is called |
| When it’s fixed | At write-time (before the code even runs) | At runtime, based on the call stack |
| Used by | JavaScript, most modern languages | Older languages like some Lisp dialects, Bash |
| Predictability | High, you can tell scope just by reading the code | Lower, scope can change depending on the call path |
JavaScript exclusively uses Lexical Scope. This is exactly why you can read a function’s code and know precisely which variables it can access, without needing to trace every possible place that function might get called from.
Also read: Best Tips and Tricks for JavaScript Debugging Skills [2026]
Why Lexical Scope Is Predictable
Unlike some languages that determine scope at runtime, JavaScript uses static scoping, also known as lexical scoping.

This makes JavaScript:
- Easier to reason about
- Easier to debug
- Safer when it comes to large applications.
When developers ask what is lexical scope in JavaScript, they are really asking how JavaScript maintains consistency and structure in complex programs.
Also read: Best Tips and Tricks for JavaScript Debugging Skills [2026]
Nested Functions and Lexical Scope in JavaScript
Lexical Scope in JavaScript really shows its value once functions get nested inside each other.
function parent() {
let parentVar = "I am from parent";
function child() {
let childVar = "I am from child";
console.log(parentVar);
console.log(childVar);
}
child();
}
parent();
Why this works:
child()is physically written insideparent()- That lets
child()reach up and readparentVar - Scope only flows outward, never inward, a parent function can never access variables declared inside its child
Also read: Best JavaScript Frameworks in 2026
Invalid Access Example
function parent() {
function child() {
let secret = "hidden";
}
// console.log(secret); // Error
}
This fails because scope only flows outward. parent() has no way to reach into child() and read secret, since secret was never declared in parent()‘s own scope or anywhere above it.
Lexical Environment and the Scope Chain in JavaScript
Every time JavaScript runs a piece of code, it builds something called a lexical environment, the backbone of Lexical Scope in JavaScript.
A lexical environment holds:
- Variable declarations
- Function declarations
- A reference to the outer lexical environment it’s nested inside
Each function’s lexical environment links back to its parent’s, and that chain of links is what’s actually called the scope chain.
When JavaScript can’t find a variable in the current scope, it walks up this chain, environment by environment, until it finds the variable or runs out of chain and throws a ReferenceError.
Also read: Best 5 Reasons to learn JavaScript in regional languages
Lexical Scope and Closures
One of JavaScript’s most powerful features, closures, depends entirely on Lexical Scope in JavaScript to work.
function greeting(name) {
return function () {
console.log("Hello, " + name);
};
}
const greetUser = greeting("Vishalini");
greetUser();
What’s happening internally:
greetUserremembersname, even thoughgreeting()already finished running- The outer function’s job is technically done, but its lexical environment isn’t thrown away
- The inner function keeps a live reference to that outer environment
- This is the exact memory mechanism that lexical scope makes possible
Without understanding Lexical Scope in JavaScript, closures feel like pure magic. Once you do understand it, they’re just a predictable consequence of how JavaScript remembers where functions were defined.
If you want to explore JavaScript through a self-paced course, try HCL GUVI’s JavaScript course.
Lexical Scope with var, let, and const
var and Lexical Scope
- Function-scoped, not block-scoped
- Can produce genuinely confusing, unpredictable behavior in loops
for (var i = 0; i < 3; i++) { console.log(i); } console.log(i); // 3
let and const
- Block-scoped
- Safer and the modern default choice
- Strongly preferred in real, current codebases
for (let i = 0; i < 3; i++) { console.log(i); } // console.log(i); Error
With let and const, Lexical Scope in JavaScript behaves far more intuitively than it does with var.
Common Lexical Scope Confusions
Confusion 1: Function Call vs Function Definition
let value = 10;
function display() {
console.log(value);
}
function run(fn) {
let value = 20;
fn();
}
run(display); // logs 10
Why 10, not 20? Because lexical scope depends on where display was defined (the global scope, where value is 10), not where it’s called from (inside run, where a different value happens to be 20).
Confusion 2: Shadowing Variables
let count = 5;
function example() {
let count = 10;
console.log(count); // 10
}
example();
console.log(count); // 5
This is called variable shadowing, the inner count temporarily hides the outer one within its own scope, and it’s entirely a consequence of Lexical Scope in JavaScript.
Also read: Master Backend Development With JavaScript | Become a Pro
Arrow Functions and Lexical Scope
Arrow functions follow the same Lexical Scope in JavaScript rules as regular functions, plus a bit more.
They additionally inherit:
- Lexical
this, meaningthisinside an arrow function refers tothisfrom the surrounding code, not its own - Lexical
arguments, in the sense that arrow functions don’t have their ownargumentsobject and instead see the enclosing scope’s let language = “JavaScript”; const showLang = () => { console.log(language); }; showLang();
Real-World Importance of Lexical Scope
- Helps write clean and well-structured JavaScript code
- Prevents common errors like undefined variables
- Controls where variables can be accessed
- Makes debugging easier and faster
- Essential for understanding closures
- Plays a key role in asynchronous JavaScript
- Widely used in modern frameworks and libraries
- Improves code scalability and maintainability
- Frequently asked concept in JavaScript interviews
Kickstart your Full Stack Development journey by enrolling in HCL GUVI’s certified Full Stack Development Course with Placement Assistance where you will master the MERN stack (MongoDB, Express.js, React, Node.js) and build interesting real-life projects.
Wrapping it up
When learning about lexical scope in JavaScript, it can seem abstract at first. However, once you have learned what it is, the language is much easier to reason about. Many bugs will go away simply because you will understand where variables are stored and how they can be resolved/located by the JavaScript engine.
If you understand what lexical scoping is in JavaScript, you will be able to do more than just write code; you will be able to think like a JavaScript engine.
FAQs
1) Is Block Scope the Same as Lexical Scope?
No, Lexical Scope is determined mostly by where you initially declare the variable in your code, whereas Block Scope is determined by where that variable exists in the code before or after it is actually declared.
2) Does Var Follow Lexical Scope?
Yes, but there is also Function Scope associated with var Declared Variables which could sometimes lead to non-predictive behavior.
3) Do Arrow Functions Follow Lexical Scope?
Yes, Arrow Functions utilize Lexical Scope, but they also inherit Lexical This.
4) What Is The Importance Of Lexical Scope In JavaScript?
Predictability of Code, Reduced Bugs, Closures.



Did you enjoy this article?