Closures in JavaScript: Understanding and Applications

A closure is a function that has access to variables in its parent scope, even after the parent function has returned. Think of it as a function with a backpack that contains the variables.

In closures, the inner function can access the variable in the outer function's scope, but the outer function cannot access the variables within the inner function.

function outerFunction(x) {
  let y = 10;
  return function innerFunction() {
    return x + y;
  };
}

let closure = outerFunction(5);
console.log(closure()); // 15

In the example, we define a function called outerFunction which takes in a single argument x. Inside the function, we define a variable y which is assigned the value of 10. The outerFunction then returns another function called innerFunction.

The innerFunction does not take any arguments, and it simply returns the sum of x and y by using the return statement.

Now, when we call outerFunction(5), it assigns the value of 5 to the variable x and creates a new execution context. Then, it assigns the value of 10 to the variable y. Once the outerFunction finishes executing, it returns the innerFunction and the execution context is destroyed.

The returned function is assigned to the variable closure. Now, when we call the closure function, it is able to access the variables x and y from its parent scope, even though the outerFunction has returned. The closure has "remembered" the values of x and y and continues to use them. So when we call closure() it returns 5 + 10 = 15.

Closures are useful when you want a function to remember certain values from its parent scope, even after the parent function has returned. This way, you can create functions with "memory", which can be used in a variety of ways such as creating private variables, methods and handling callbacks and events.

Uses of Closures

Closures have a variety of uses in JavaScript, some of the most common are:

  1. Creating private variables and methods: Closures can be used to create private variables and methods within a function, which cannot be accessed or modified from outside the function.
function createCounter() {
  let count = 0;
  return {
    increment() {
      count++;
    },
    decrement() {
      count--;
    },
    getCount() {
      return count;
    },
  };
}

let counter = createCounter();
console.log(counter.getCount()); // 0
counter.increment();
console.log(counter.getCount()); // 1
counter.decrement();
console.log(counter.getCount()); // 0

In this example, the createCounter function creates an object with three methods: increment, decrement, and getCount. The count variable is defined within the scope of the createCounter function, making it private and inaccessible from outside the function.

  1. Event handling: Closures can be used in event handling to maintain the state of a variable or object, even after the event has finished executing.
let button = document.getElementById("myButton");
let count = 0;

button.addEventListener("click", function () {
  count++;
  console.log("Button clicked: " + count + " times");
});

In this example, the event listener is attached to a button element and uses a closure to maintain the state of the count variable, even after the event has finished executing.

  1. Callbacks: Closures can be used to pass a function as a parameter to another function, known as a callback. The callback function can retain access to the variables in its parent scope, even after the parent function has finished executing.
function calculateSum(a, b, callback) {
  let result = a + b;
  callback(result);
}

calculateSum(5, 10, function (sum) {
  console.log("The sum is: " + sum);
});

In this example, the calculateSum function takes in two numbers and a callback function as arguments. The callback function is passed to the calculateSum function as a closure, allowing it to retain access to the result variable, even after the calculateSum function has finished executing.

  1. Modules: Closures can be used to create modules, which are self-contained units of code that can be reused throughout an application.
let myModule = (function () {
  let privateVariable = "I am private";
  function privateFunction() {
    console.log(privateVariable);
  }
  return {
    publicVariable: "I am public",
    publicFunction: function () {
      privateFunction();
    },
  };
})();

console.log(myModule.publicVariable); // "I am public"
myModule.publicFunction(); // "I am private"

In this example, the myModule variable is assigned the return value of an immediately invoked function expression

Conclusion

In conclusion, closures are a powerful feature in JavaScript that allows a function to retain access to the variables in its parent scope even after the parent function has returned. This allows the closure to "remember" the values of those variables and continue to use them. Closures are often used to create private variables, methods and handling callbacks and events. Closures are an important concept to understand when working with JavaScript and mastering it can give you a lot of control over your code and make it more powerful.

You may also like my other articles:

  1. Why is System Design Important?
  2. Building Real-time Applications with Redis Pub/Sub
  3. Architecture and Design Principle for Online Food Delivery System

💌 If you'd like to receive more tutorials in your inbox, you can sign up for the newsletter here.

Please let me know if there's anything else I can add or if there's any way to improve the post. Also, leave a comment if you have any feedback or suggestions.

Discussions

Up next