DEV Community

Cover image for Understanding Lexical Scope in JavaScript ✅
Ali Samir
Ali Samir

Posted on

Understanding Lexical Scope in JavaScript ✅

JavaScript, like many other programming languages, relies on a concept called "lexical scope" (also known as static scope) to resolve variable references within nested functions.

This article will delve into what lexical scope is, how it works, and why it is fundamental to mastering JavaScript.


What is Lexical Scope?

Lexical scope refers to the region in the source code where a variable is defined.

In JavaScript, the scope of a variable is determined by its location within the nested function blocks.

The key idea is that inner functions have access to variables declared in their outer functions.

This accessibility is determined at the time the code is written, not at runtime, which is why it is called "lexical" (relating to the text or source code).


How Lexical Scope Works?

When JavaScript code is executed, it creates a chain of scope environments, known as the "scope chain".

Each function creates its own scope, and if a variable is not found in the current function's scope, JavaScript looks up the scope chain to find it.

Consider the following example:

function outerFunction() {
    let outerVar = 'I am outside!';

    function innerFunction() {
        console.log(outerVar); // Can access outerVar due to lexical scope
    }

    innerFunction();
}

outerFunction();
Enter fullscreen mode Exit fullscreen mode

In this code:

  • outerFunction creates a scope that includes the variable outerVar.
  • innerFunction, defined within outerFunction, can access outerVar because it is within its lexical scope.

When innerFunction is called, JavaScript first looks for outerVar within innerFunction. Not finding it there, it then looks in the scope of outerFunction, where it finds and logs the variable.


Nested Lexical Scopes

Lexical scope can nest to multiple levels. Each inner function has access to its own scope, the scope of its parent function, and so on up the scope chain.

function firstFunction() {
    let firstVar = 'First level';

    function secondFunction() {
        let secondVar = 'Second level';

        function thirdFunction() {
            let thirdVar = 'Third level';
            console.log(firstVar);   // Logs 'First level'
            console.log(secondVar);  // Logs 'Second level'
            console.log(thirdVar);   // Logs 'Third level'
        }

        thirdFunction();
    }

    secondFunction();
}

firstFunction();
Enter fullscreen mode Exit fullscreen mode

Here:

  • thirdFunction can access secondVar and firstVar because of the lexical scope chain.
  • Each function's scope can access variables from its parent scopes but not vice versa.

Lexical Scope vs. Dynamic Scope

It is important to distinguish between lexical scope and dynamic scope:

  1. Lexical scope is determined by the placement of the code in the source file. The scope chain is established at the time the code is written.

  2. Dynamic scope is determined at runtime, based on the call stack. JavaScript uses lexical scope, not dynamic scope.

Consider a language with dynamic scope, where functions would access variables based on the calling context. This is not how JavaScript operates.


Closures and Lexical Scope

Closures are a powerful feature of JavaScript that leverage lexical scope.

A closure is created when an inner function retains access to its outer function’s scope even after the outer function has finished execution.

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
Enter fullscreen mode Exit fullscreen mode

In this example:

  • makeCounter defines a variable count and returns an inner function that increments and returns count.
  • Even after makeCounter has executed and returned, the inner function retains access to count because of the closure created by lexical scope.

Benefits of Lexical Scope

Lexical scope simplifies the mental model needed to understand variable resolution in JavaScript.

Since scope is determined by the code structure, it is predictable and easier to debug.

This predictability makes JavaScript a more robust language for large-scale applications.


Conclusion

Lexical scope is a cornerstone concept in JavaScript, dictating how variables are resolved in nested functions.

By understanding lexical scope, developers can write more predictable and maintainable code, leveraging closures to create powerful abstractions.

Mastering this concept is essential for anyone looking to become proficient in JavaScript.


Happy Coding! 🔥

Top comments (0)