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 -> null

Example 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 environment

Example 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