Understanding Closure in JavaScript

Understanding Closure in JavaScript

Dipesh Chaulagain
Dipesh Chaulagain

3. Closure

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function.

  • A function retains access to its lexical scope even when the function is executed outside that scope.
  • Remember the environment in which function is created.
function outerFunction() {
  let outerVariable = 'I am from the outer function';

  function innerFunction() {
    console.log(outerVariable);
  }

  return innerFunction;
}

const myClosure = outerFunction();
myClosure(); // Output: I am from the outer function

Lexical Scope

Lexical scope means that the scope of a variable is determined by its location within the source code. In JavaScript, functions can access variables from their own scope, the scope of the parent function, and the global scope.

Function Creation

When a function is created, it retains a reference to its lexical scope. This means it keeps a reference to the variables and functions in the scope where it was defined.

Function Execution

Even when the function is executed outside its original scope, it still has access to the variables that were in scope when it was created. This combination of the function and its lexical environment forms a closure.

Use Case 1: Encapsulation

Closures can be used to create private variables that cannot be accessed from outside a function.

function createCounter() {
  let count = 0;
  return {
    increment: function () {
      count++;
      return count;
    },
    decrement: function () {
      count--;
      return count;
    },
  };
}

Use Case 2: Partial Application and Currying

Closures can be used to create functions that fix some of their arguments and wait for the remaining ones.

function multiply(x) {
  return function (y) {
    return x * y;
  };
}

Use Case 3: Maintaining State

Closures are useful for maintaining state in an asynchronous environment, such as in event handlers or timers.

function setup() {
  let name = 'JavaScript';
  setTimeout(function () {
    console.log(name);
  }, 1000);
}

setup(); // After 1 second, logs: JavaScript

Currying

Currying is a functional programming technique that involves breaking down a function that takes multiple arguments into a series of functions that take one argument each. This creates a chain of functions, where each function returns another function until the final result is achieved.

  1. Reusability: Currying breaks down a complex function into smaller, reusable units. Each curried function focuses on a single argument, making it easier to understand and maintain. These smaller functions can be reused across different parts of your codebase.
  2. Partial Function Application: Currying allows you to create partially applied functions, where you fix some of the arguments in advance and leave the rest to be supplied later. This is useful when you have a function that requires some parameters to be the same across multiple calls.
  3. Code Composition: Currying encourages the creation of new functions by composing existing ones. The currying function in JavaScript is a higher-order function. Higher-order functions are those that either take another function as an argument or return a function. It uses functional programming which results in cleaner, more expressive code.