How dose JavaScript Closure Work with Example

JavaScript closure

In JavaScript, a closure is a function that has access to variables in its outer (enclosing) function’s scope chain. A closure can access variables in its own scope, as well as variables in the scope of the outer function.

A closure is created when a function is defined inside another function, and the inner function uses variables from the outer function. The inner function maintains a reference to the outer function’s scope, even after the outer function has returned.

Here’s an example of a closure in JavaScript:

JavaScript
function outer() {
  var x = 10;
  function inner() {
    console.log(x);
  }
  return inner;
}

var closure = outer();
closure(); 

Output:

10

In this example, ‘outer()‘ is a function that defines a variable ‘x‘ and returns the inner function ‘inner()‘. ‘inner()‘ has access to ‘x‘ in the scope of ‘outer()‘, even though ‘outer()‘ has already returned. When we call ‘closure()‘, it logs the value of ‘x‘, which is 10.

Closures are commonly used in JavaScript to create private variables and functions. By defining a function inside another function, you can create a private scope for the inner function that is not accessible from outside the outer function. This can be useful for hiding implementation details and preventing conflicts with other code.

Closures can be a powerful tool in JavaScript programming, but they can also be a source of confusion if not used carefully. It’s important to understand how closures work and how to use them effectively to avoid common pitfalls.

Use of closure

Closures are used in JavaScript for a variety of purposes, but some of the most common use cases include:

  1. Creating private variables and functions: Closures allow you to create variables and functions that are only accessible within the scope of a parent function. This can be useful for hiding implementation details and preventing conflicts with other code.
  2. Preserving state: Closures allow you to “remember” the state of a function between calls. This can be useful for functions that need to maintain some internal state, such as event handlers or animation functions.
  3. Creating higher-order functions: Closures can be used to create functions that generate other functions. This can be useful for creating reusable code and reducing duplication.
  4. Managing asynchronous code: Closures can be used to manage asynchronous code, such as callbacks or promises, by capturing the state of a function when it is called and passing that state along to the asynchronous code.

Overall, closures are a powerful tool in JavaScript that can be used to create flexible and modular code. However, they can also be a source of confusion and bugs if not used carefully, so it’s important to understand how closures work and how to use them effectively.

Creating private variables and functions:

In JavaScript, closures can be used to create private variables and functions. Here’s an example:

JavaScript
function counter() {
  var count = 0; // private variable
  function increment() { // private function
    count++;
    console.log(count);
  }
  return increment;
}

var myCounter = counter(); // create a new counter
myCounter(); 
myCounter(); 
myCounter(); 

Output:

1
2
3

In this example, ‘counter()‘ is a function that defines a private variable count and a private function ‘increment()‘. ‘increment()‘ can access ‘count‘ because it is defined within the same scope. ‘counter()‘ returns ‘increment()‘, which is a closure that has access to ‘count‘.

We then create a new counter by calling ‘counter()‘, and assign it to the variable ‘myCounter‘. When we call ‘myCounter()‘, it logs the current value of ‘count‘ and increments it. Since ‘myCounter()‘ is a closure that has access to ‘count‘, it can maintain the state of the counter between calls.

Note that the private variable ‘count‘ and the private function ‘increment()‘ are not accessible from outside the ‘counter()‘ function. This allows us to create a private “namespace” for our counter that does not conflict with other code in the global scope.

Overall, closures can be a powerful tool for creating private variables and functions in JavaScript. By using closures to create private scopes, we can reduce the risk of naming conflicts and create more modular and maintainable code.

Preserving state

In JavaScript, closures can be used to preserve the state of a function between calls. Here’s an example:

JavaScript
function createCounter(initialValue) {
  var count = initialValue;
  function increment() {
    count++;
    console.log(count);
  }
  function reset() {
    count = initialValue;
    console.log(count);
  }
  return { increment: increment, reset: reset };
}

var myCounter = createCounter(0); // create a new counter with initial value of 0
myCounter.increment(); 
myCounter.increment(); 
myCounter.reset(); 

Output:

1
2
0

In this example, createCounter() is a function that defines a private variable count and two private functions increment() and reset(). increment() can access and modify count, and reset() can reset count to the initial value.

createCounter() returns an object with two methods: increment() and reset(). Since these methods are closures that have access to the private variable count, they can maintain the state of the counter between calls.

We then create a new counter by calling createCounter() with an initial value of 0, and assign it to the variable myCounter. When we call myCounter.increment(), it logs the current value of count and increments it. When we call myCounter.reset(), it resets count to the initial value of 0.

Overall, closures can be a powerful tool for preserving state in JavaScript. By using closures to maintain the state of a function between calls, we can create more flexible and reusable code.

Creating higher-order functions

In JavaScript, closures can be used to create higher-order functions. A higher-order function is a function that takes one or more functions as arguments and/or returns a function as its result. Here’s an example of a higher-order function that uses closures:

JavaScript
function multiplyBy(multiplier) {
  return function(number) {
    return number * multiplier;
  };
}

var double = multiplyBy(2); // create a new function that multiplies by 2
var triple = multiplyBy(3); // create a new function that multiplies by 3

console.log(double(5)); 
console.log(triple(5)); 

Output:

10
15

In this example, multiplyBy() is a higher-order function that takes a multiplier argument and returns a new function. The new function is a closure that has access to the multiplier argument and can multiply its argument by multiplier.

We then create two new functions, double and triple, by calling multiplyBy() with arguments of 2 and 3, respectively. These functions are closures that have access to the multiplier argument of multiplyBy(), which allows them to multiply their argument by 2 or 3.

When we call double(5), it multiplies 5 by 2 and returns 10. When we call triple(5), it multiplies 5 by 3 and returns 15.

Overall, closures can be a powerful tool for creating higher-order functions in JavaScript. By using closures to generate new functions with specific behaviors, we can create more flexible and reusable code.

Managing asynchronous code

Closures can be used to manage asynchronous code in JavaScript by creating functions that retain their scope and state even after they have been called.

One common technique for managing asynchronous code using closures is to use a callback function. A callback function is a function that is passed as an argument to another function and is executed when the other function has completed its task.

Here’s an example of how closures can be used to manage asynchronous code with a callback function:

JavaScript
function fetchData(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
      var data = JSON.parse(xhr.responseText);
      callback(data);
    }
  };
  xhr.open('GET', url, true);
  xhr.send();
}

function displayData(data) {
  console.log(data);
}

fetchData('https://example.com/api/data', displayData);

In this example, fetchData() is a function that takes a URL and a callback function as arguments. It uses the XMLHttpRequest object to make an asynchronous HTTP request to the specified URL, and when the response is received, it calls the callback function with the parsed data as its argument.

We then define a displayData() function that simply logs the data to the console.

Finally, we call fetchData() with the URL and the displayData() function as arguments. When the response is received, fetchData() calls displayData() with the parsed data as its argument.

This example demonstrates how closures can be used to manage asynchronous code by retaining the scope and state of the callback function even after it has been passed as an argument and called by another function.

Share The Tutorial With Your Friends
Twiter
Facebook
LinkedIn
Email
WhatsApp
Skype
Reddit

Check Our Ebook for This Online Course

Advanced topics are covered in this ebook with many practical examples.