Understanding JavaScript Closures

A key idea in JavaScript is closures, which enable functions to keep access to their lexical scope even when they are being used outside of it. This implies that a function can retain the context in which it was developed, which is especially helpful for encapsulating data and preserving state.

What is a Closure in JavaScript?

When a function is defined inside another function, it creates a closure that permits the inner function to access variables from the scope of the outer function. This is essential for JavaScript private variable and function creation.

As an illustration

function outerFunction() {
    let outerVariable = 'I am from outer scope';

    function innerFunction() {
        console.log(outerVariable); // Accessing outerVariable
    }
    return innerFunction;
}
const myClosure = outerFunction();
myClosure();

Closure

In this instance, innerFunction is a closure that, even after outerFunction has completed its execution, maintains access to outerVariable.

Practical Uses of Closures
 

Data privacy

Private variables can be created using closures. You can stop outside variables from being accessed directly by returning an inner function that accesses the variables of the outer function.

As an illustration

function createCounter() {
    let count = 0; // Private variable

    return {
        increment: function () {
            count++;
            return count;
        },
        decrement: function () {
            count--;
            return count;
        },
        getCount: function () {
            return count;
        },
    };
}

const counter = createCounter();
console.log(counter.increment()); // Outputs: 1
console.log(counter.increment()); // Outputs: 2
console.log(counter.getCount());  // Outputs: 2

Data privacy

Function Factories

Functions with predefined parameters can be created using closures.

As an illustration

function multiplyBy(factor) {
    return function (x) {
        return x * factor;
    };
}
const double = multiplyBy(2);
console.log(double(7)); // Outputs: 14

Return Function

Event Handlers

In event handlers, closures are frequently used to preserve access to variables within the scope in which the handler was developed.

As an illustration

<!DOCTYPE html>
<html>
  <body>
    <h2>Event Handlers</h2>
    <button type="button" id="myButton">Click Me!</button>
    <p id="txtMsg"></p>

    <script>
      function setupButton(buttonId) {
        let button = document.getElementById(buttonId);
        let txtMsg = document.getElementById('txtMsg');
        let count = 0;

        button.addEventListener('click', function () {
          count++;
          txtMsg.innerHTML = `Button clicked ${count} times`;
        });
      }

      setupButton('myButton');
    </script>
  </body>
</html>

Event handler

Conclusion

Data encapsulation, function factories, and other uses are made possible by JavaScript's powerful closures feature, which allows functions to retain access to their lexical scope. Writing efficient, maintainable code and becoming proficient with JavaScript requires an understanding of closures.

We learned the new technique and evolved together.

Happy coding!