⬅ Previous Topic
JavaScript Scope – Global, Local, BlockNext Topic ⮕
JavaScript Hoisting⬅ Previous Topic
JavaScript Scope – Global, Local, BlockNext Topic ⮕
JavaScript HoistingIn JavaScript, lexical scope (also called static scope) means that the accessibility of variables is determined by the position of functions and blocks in the source code — not at runtime, but when the code is written. In simpler terms, inner functions have access to variables defined in their outer (parent) scopes.
function outerFunction() {
let outerVariable = "I'm from the outer function";
function innerFunction() {
console.log(outerVariable);
}
innerFunction();
}
outerFunction();
I'm from the outer function
Here, innerFunction
is defined inside outerFunction
, so it has access to outerVariable
due to lexical scoping. JavaScript knows this during the time of writing the code, not at runtime.
When a variable is accessed, JavaScript looks for it in the current scope. If it's not found, it walks up the scope chain — all the way to the global scope if necessary.
let globalVar = "Global";
function levelOne() {
let levelOneVar = "Level 1";
function levelTwo() {
let levelTwoVar = "Level 2";
console.log(globalVar); // Accessible
console.log(levelOneVar); // Accessible
console.log(levelTwoVar); // Accessible
}
levelTwo();
}
levelOne();
Global
Level 1
Level 2
function outer() {
let outerVar = "outer";
function inner() {
let innerVar = "inner";
console.log(outerVar); // Works
}
inner();
console.log(innerVar); // ❌ Error: innerVar is not defined
}
outer();
outer
Uncaught ReferenceError: innerVar is not defined
Lexical scope only applies to nested relationships, not sibling functions.
function one() {
let msg = "from one";
}
function two() {
console.log(msg); // ❌ Error
}
one();
two();
Uncaught ReferenceError: msg is not defined
Each function creates its own lexical environment. Inner functions carry a reference to their parent's scope. Let's visualize that:
function grandParent() {
let gp = "grandparent";
function parent() {
let p = "parent";
function child() {
console.log(gp); // ✅
console.log(p); // ✅
}
child();
}
parent();
}
grandParent();
grandparent
parent
function authenticate(username) {
let secret = "token_" + username;
function getToken() {
return secret;
}
return getToken;
}
const tokenFetcher = authenticate("JohnDoe");
console.log(tokenFetcher()); // Lexical scope retains 'secret'
token_JohnDoe
A closure happens when a function "remembers" its lexical scope even after the outer function has finished executing.
function counter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const increment = counter();
increment(); // 1
increment(); // 2
increment(); // 3
1
2
3
Lexical scope is a core concept that gives JavaScript its power and flexibility. Mastering it lays the foundation for understanding closures, module patterns, and advanced concepts like currying and memoization. Always remember — where you write your functions matters just as much as how you write them.
⬅ Previous Topic
JavaScript Scope – Global, Local, BlockNext Topic ⮕
JavaScript HoistingYou can support this website with a contribution of your choice.
When making a contribution, mention your name, and programguru.org in the message. Your name shall be displayed in the sponsors list.