DEV Community

Jyoti chaudhary
Jyoti chaudhary

Posted on

Closure in JavaScript

A closure is the combination of a function and the lexical environment within which that function was declared.
OR
A closure in JavaScript is a function that remembers its lexical scope (the scope in which it was created) even when it is executed outside that scope. This means that a function can "remember" the environment in which it was created, including any variables that were in scope at the time.

Imagine you want to speed posting some documents. You put all the documents in an envelope and sealed it. All the documents are inside the envelope and after speed posting from one place to another, the documents are still inside it. Similarly, a closure "remembers" the variables from the place where it was created, even after it moves to a different place in the code.

Lexical Scoping:

JavaScript functions are lexically scoped, meaning that they can access variables from the surrounding code in which they were defined, even if that surrounding code is no longer in execution.

In simple terms:
  • Lexical scope means that the scope of a variable is defined by where it is written in the code, not where it is called from.
  • A closure captures variables from the outer scope at the time the function is created, not when it is called.
How does closure work?

In a closure, when a function is declared inside another function, it gets access to the outer function's variables. Even after the outer function has finished executing, the inner function retains access to those variables.

1: Basic Closure Example:
function outerFunction() {
  let outerVariable = 'I am outside!';

  function innerFunction() {
    console.log(outerVariable);  // Inner function uses outerVariable
  }

  return innerFunction;
}

const closureFunc = outerFunction();  // Call the outer function
closureFunc();  // Even though outerFunction is done, innerFunction can still access outerVariable

// Output: I am outside!

Enter fullscreen mode Exit fullscreen mode
Explanation:
  1. outerFunction has a variable called outerVariable and it returns another function (called innerFunction).
  2. When outerFunction() is called, it returns the innerFunction.
  3. Even though outerFunction has finished executing by the time closureFunc is called, the innerFunction still remembers the outerVariable that was declared in the outer function. This is the closure.
2: Closure with Arguments:
function multiplier(x) {
  return function(y) {
    return x * y;
  }
}

const multiplyBy = multiplier(5);
console.log(multiplyBy(10));  // Output: 50
console.log(multiplyBy(6));  // Output: 30

Enter fullscreen mode Exit fullscreen mode
Explanation:
  1. multiplier is a function that takes a parameter x and returns an inner function.
  2. The inner function takes a parameter y and returns the multiply of x and y.
  3. When we call multiplier(5), it returns a new function that multiplies 5 by any number passed into it.
  4. Each call to multiplyBy remembers x = 5 (from the outer scope) and can access it to calculate the result.
3: Closures and SetTimeout
function createCounter() {
    let count = 0;

    function innerCounter() {
      count++;
      console.log(count);
    }
  return innerCounter;
  }

  const counter = createCounter();
  counter();                  // Immedietely Output 1
  setTimeout(counter, 1000);  // Output after 1 second: 2
  setTimeout(counter, 2000);  // Output after 2 seconds: 3
  setTimeout(counter, 3000);  // Output after 3 seconds: 4

Enter fullscreen mode Exit fullscreen mode
Explanation:
  1. The function createCounter defines a variable count and returns a function innerCounter that increments count each time it is called.
  2. Even though createCounter has finished executing, the returned function (the closure) still "remembers" count.
  3. The setTimeout calls invoke the returned function, and the counter continues to increment as expected.
4: Practical Use of Closure (Data Encapsulation)
function Counter() {
  let count = 0;  // private variable

  this.increment = function() {
    count++;
    console.log(count);
  }

  this.decrement = function() {
    count--;
    console.log(count);
  }

  this.getCount = function() {
    return count;
  }
}

const myCounter = new Counter();
myCounter.increment(); // Output: 1
myCounter.increment(); // Output: 2
myCounter.decrement(); // Output: 1
console.log(myCounter.getCount()); // Output: 1

Enter fullscreen mode Exit fullscreen mode
Explanation:
  1. The Counter function acts as a constructor, defining a private variable count.
  2. The methods increment, decrement, and getCount form closures because they have access to the count variable.
  3. Outside code cannot directly access or modify count; it can only interact with it via the provided methods.
Why Closures are Important?
  • Data Privacy/Encapsulation: You can create private variables that cannot be accessed directly from the outside world, but can still be manipulated via functions (like in the Counter example above).
  • Function Factories: Closures allow you to create customized versions of a function, like the makeAdder example.
  • Asynchronous Programming: Closures are useful in scenarios like asynchronous code, where functions need to "remember" their environment (like the setTimeout example).
Performance Consideration

While closures are a powerful tool, they come with some potential performance implications:

  • Memory Usage: A closure can keep a reference to its outer variables, potentially leading to higher memory usage. If you create many closures that capture large amounts of data, it could slow down the application.
  • Garbage Collection: Closures may delay the garbage collection of variables they capture. If you no longer need the closure, ensure you release references to it.
Key Concept:
  • A closure is created when a function has access to its parent function’s variables, even after the parent function has finished executing.
  • The inner function "closes over" the variables from the outer function, which is why it’s called a closure.

Top comments (1)

Collapse
 
razielrodrigues profile image
Raziel Rodrigues

Nice