Lexical Environment
What is Lexical Environment?
A lexical environment is a structure that holds identifier-variable mapping. It consists of an Environment Record (stores variables and functions) and a reference to the outer environment.
Try Lexical Environment
Code Editor
Console Output
Click "Run" to execute your code...
Example 1: Lexical Environment Basics
// Global Lexical Environment
var globalVar = 'Global';
let globalLet = 'Global Let';
function outer() {
// outer() Lexical Environment
var outerVar = 'Outer';
function inner() {
// inner() Lexical Environment
var innerVar = 'Inner';
console.log(innerVar); // Found in inner's environment
console.log(outerVar); // Found in outer's environment
console.log(globalVar); // Found in global environment
}
inner();
}
outer();
// Lexical Environment Chain:
// inner() -> outer() -> Global -> nullExample 2: Lexical Scoping
function init() {
var name = 'Mozilla'; // name is a local variable created by init
function displayName() {
// displayName() is the inner function, a closure
console.log(name); // Uses variable from parent function
}
displayName();
}
init(); // Mozilla
// displayName() has access to 'name' because it's in its lexical scope
// The function was defined in init's scope, so it can access init's variables
// Example with multiple nested functions
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// The returned function "remembers" its lexical environmentExample 3: Lexical Environment and 'this'
const obj = {
name: 'Object',
regularFunction: function() {
console.log(this.name); // 'this' depends on how function is called
const arrowFunc = () => {
console.log(this.name); // Arrow function inherits 'this' lexically
};
arrowFunc();
}
};
obj.regularFunction();
// Output:
// Object
// Object
// Compare with regular function:
const obj2 = {
name: 'Object2',
regularFunction: function() {
console.log(this.name); // Object2
function innerFunc() {
console.log(this.name); // undefined (or error in strict mode)
}
innerFunc();
}
};
obj2.regularFunction();Example 4: Lexical Environment in Loops
// Problem with var (shares lexical environment)
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 3, 3, 3 (all reference same 'i')
}, 1000);
}
// Solution with let (creates new lexical environment per iteration)
for (let j = 0; j < 3; j++) {
setTimeout(function() {
console.log(j); // 0, 1, 2 (each has its own 'j')
}, 1000);
}
// Solution with IIFE and var
for (var k = 0; k < 3; k++) {
(function(x) {
setTimeout(function() {
console.log(x); // 0, 1, 2 (captured in IIFE's environment)
}, 1000);
})(k);
}Example 5: Practical Use - Module Pattern
const calculator = (function() {
// Private variables (in this lexical environment)
let result = 0;
// Private function
function log(message) {
console.log(`[${message}] Result: ${result}`);
}
// Public API
return {
add: function(x) {
result += x;
log('ADD');
return this;
},
subtract: function(x) {
result -= x;
log('SUBTRACT');
return this;
},
getResult: function() {
return result;
},
reset: function() {
result = 0;
log('RESET');
return this;
}
};
})();
calculator.add(10).add(5).subtract(3);
console.log(calculator.getResult()); // 12
// console.log(calculator.result); // undefined (private!)
calculator.reset();Key Points
- Lexical environment consists of Environment Record and outer reference
- Lexical scope is determined by where code is written, not where it's called
- Inner functions have access to variables in their outer lexical environment
- Each function call creates a new lexical environment
- Arrow functions don't create their own 'this', they inherit it lexically
- Closures are functions that remember their lexical environment