JavaScript Notes
Master JavaScript lexical scope: scope chain, static vs dynamic scope, closures, nested functions, block scope, and essential interview Q&A with diagrams.
What is Lexical Scope?
Lexical scope (also called static scope) means that a variable's accessibility is determined by where the function is written in the source code — not where it is called from.
JavaScript's scope rules are decided at write time (when you type your code), not at run time (when the code actually executes).
One-liner: In JavaScript, a function can access variables from the place where it was defined, not where it was called.
Lexical vs Dynamic Scope
| Feature | Lexical Scope (JavaScript) | Dynamic Scope |
|---|---|---|
| Determined by | Where function is written | Where function is called |
| Predictability | ✅ Predictable — just read code | ❌ Hard to predict |
| Used in | JavaScript, C, Java, Python | Bash, early Lisp |
| Example result | See definition context | See call context |
Basic Example
const city = "Mumbai"; // Global scope
function showCity() {
console.log(city); // Can access global `city`
}
function outer() {
const name = "WoHoTech";
function inner() {
console.log(name); // Can access outer's `name`
console.log(city); // Can access global's `city`
}
inner();
}
showCity();
outer();Mumbai WoHoTech Mumbai
inner() can access name because it's defined inside outer(). It can access city because it's defined inside the global scope. The call location doesn't matter.
Scope Chain Visualization
The Scope Chain
The scope chain is the series of nested scopes JavaScript walks through to find a variable:
Variable Lookup Process:
inner() scope → outer() scope → global scope → ReferenceError
Each scope has an "outer reference" pointing to the scope where it was defined.const global = "GLOBAL";
function level1() {
const l1 = "L1";
function level2() {
const l2 = "L2";
function level3() {
const l3 = "L3";
console.log(l3); // Found in level3
console.log(l2); // Found in level2 via chain
console.log(l1); // Found in level1 via chain
console.log(global); // Found in global via chain
}
level3();
}
level2();
}
level1();L3 L2 L1 GLOBAL
Lexical Scope Is Fixed at Write Time
This is the key insight — call location doesn't affect scope:
const value = "GLOBAL";
function getOuter() {
const value = "OUTER";
function inner() {
return value; // Always "OUTER" — defined inside getOuter
}
return inner;
}
function callElsewhere() {
const value = "ELSEWHERE"; // Doesn't affect inner!
const fn = getOuter();
return fn(); // Still returns "OUTER" — lexical, not dynamic
}
console.log(callElsewhere());OUTER
Even though inner is called from callElsewhere() where a local value = "ELSEWHERE" exists, inner still reads value from where it was written (inside getOuter), not where it was called.
Lexical Scope Powers Closures
Closures are a direct consequence of lexical scope:
2
The methods increment, decrement, and value all have lexical access to count because they were defined inside makeCounter. Even after makeCounter returns, these functions retain access to count via closure — which lexical scope makes possible.
Lexical Scope with Block Scope (let/const)
let and const are block-scoped — the block ({}) is their lexical boundary:
Order 1: 100 Order 2: 200 Order 3: 300
Arrow Functions and Lexical this
Arrow functions take lexical this — they inherit this from where they are written (not called):
1 2 3 ...
The arrow function inside setInterval captures this from Timer's lexical scope (the Timer instance), not from setInterval's calling context.
Common Mistakes
❌ Mistake 1 — Thinking Call Location Determines Scope
let x = "global";
function readX() {
console.log(x);
}
function changeContext() {
let x = "local"; // This x is in changeContext's scope
readX(); // readX was DEFINED where global x is visible
}
changeContext();global
readX reads from where it was defined (global), not where it was called (changeContext).
❌ Mistake 2 — Thinking Variables Leak from Sibling Scopes
function siblingA() {
const data = "from A";
}
function siblingB() {
console.log(data); // ❌ ReferenceError — no access to siblingA's scope
}
siblingB();ReferenceError: data is not defined
Sibling functions share only the parent scope — not each other's local scopes.
❌ Mistake 3 — var Ignoring Block Scope
if (true) {
var leaked = "I leak outside blocks";
}
console.log(leaked); // Accessible — var is function-scoped, not block-scopedI leaked outside blocks
Use let/const for true block-scoped lexical behavior.
Interview Questions 🎯
Q1. What is lexical scope in JavaScript?
Lexical scope means a function's ability to access variables is determined by where the function was written in the source code, not where it's called. JavaScript resolves variable names by walking the scope chain from the current scope outward to the global scope.
Q2. How does the scope chain work?
When JavaScript looks up a variable, it starts in the current scope. If not found, it moves to the outer scope (where the function was defined), then to that outer scope's parent, continuing until the global scope. If not found in global, ReferenceError is thrown.
Q3. What is the difference between lexical scope and dynamic scope?
- Lexical scope (static): Variable access based on where functions are defined — JavaScript uses this
- Dynamic scope: Variable access based on where functions are called — used by Bash, early Lisp
Lexical scope is more predictable because you can determine variable access just by reading the code.
Q4. How does lexical scope enable closures?
When a function is defined inside another function, it has lexical access to the outer function's variables. Even after the outer function returns, the inner function retains a reference to those variables through its lexical scope record — that's a closure.
Q5. Does call location ever affect variable access in JavaScript?
No — variable access is always determined by the write location (lexical scope), never the call location. However, this can be affected by call location (for regular functions). Arrow functions take this lexically.
Q6. What is the difference between function scope and block scope?
- Function scope (
var): variable is accessible throughout the entire function - Block scope (
let/const): variable is accessible only within its{}block
Block scope is a subset of function scope — it creates more granular lexical boundaries.
Q7. How does lexical scope relate to closures in event handlers?
The event handler arrow function lexically captures label from setupButton. Long after setupButton returns, the click handler still accesses label via its lexical scope closure.
Q8. Can a nested function access a variable in a sibling function?
No. Two functions at the same level share access to their parent scope, but not each other's local scopes. Scope only flows outward (child → parent), never sideways (sibling → sibling).
Key Takeaways 🔑
- Lexical scope: variable access determined by where code is written, not where it runs
- JavaScript walks the scope chain outward from current scope until variable is found
- Scope chain = series of nested lexical environments linked by outer references
- Lexical scope is the foundation of closures — functions remember their definition scope
- Arrow functions inherit
thislexically (from definition context) let/constare block-scoped —varis function-scoped (ignores blocks)- Call location does not affect variable access (only
thiscan be affected)
Summary
Lexical scope is JavaScript's foundational rule for variable access: a function can access variables from the scope where it was written, not where it's called. This creates a scope chain — a hierarchy of nested scopes that JavaScript walks outward through to resolve variable names. Lexical scope directly enables closures (functions remember their definition environment), explains why arrow functions inherit this lexically, and makes code predictable (you can always determine variable access by reading the code structure). Understanding lexical scope is the key to mastering closures, scope chains, and this behavior in JavaScript.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Lexical Scope - Complete Guide with Scope Chain Diagrams.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, advanced, lexical, scope
Related JavaScript Master Course Topics