Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a practical use for a closure in JavaScript?

People also ask

Why are closures important in JavaScript?

In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

What is closure in JavaScript with real time example?

In JavaScript, closures are defined as inner functions that have access to variables and parameters of outer function even after the outer function has returned.


Suppose, you want to count the number of times user clicked a button on a webpage.

For this, you are triggering a function on onclick event of button to update the count of the variable

<button onclick="updateClickCount()">click me</button>

Now there could be many approaches like:

  1. You could use a global variable, and a function to increase the counter:

     var counter = 0;
    
     function updateClickCount() {
         ++counter;
         // Do something with counter
     }
    

    But, the pitfall is that any script on the page can change the counter, without calling updateClickCount().


  1. Now, you might be thinking of declaring the variable inside the function:

     function updateClickCount() {
         var counter = 0;
         ++counter;
         // Do something with counter
     }
    

    But, hey! Every time updateClickCount() function is called, the counter is set to 1 again.


  1. Thinking about nested functions?

    Nested functions have access to the scope "above" them.

    In this example, the inner function updateClickCount() has access to the counter variable in the parent function countWrapper():

     function countWrapper() {
         var counter = 0;
         function updateClickCount() {
             ++counter;
             // Do something with counter
         }
         updateClickCount();
         return counter;
     }
    

    This could have solved the counter dilemma, if you could reach the updateClickCount() function from the outside and you also need to find a way to execute counter = 0 only once not everytime.


  1. Closure to the rescue! (self-invoking function):

     var updateClickCount = (function(){
         var counter = 0;
    
         return function(){
             ++counter;
             // Do something with counter
         }
     })();
    

    The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.

    This way updateClickCount becomes a function. The "wonderful" part is that it can access the counter in the parent scope.

    This is called a JavaScript closure. It makes it possible for a function to have "private" variables.

    The counter is protected by the scope of the anonymous function, and can only be changed using the add function!

A more lively example on closures

<script>
var updateClickCount = (function(){
    var counter = 0;

    return function(){
        ++counter;
        document.getElementById("spnCount").innerHTML = counter;
    }
})();
</script>

<html>
<button onclick="updateClickCount()">click me</button>
<div> you've clicked
    <span id="spnCount"> 0 </span> times!
</div>
</html>

Reference: JavaScript Closures


I've used closures to do things like:

a = (function () {
    var privatefunction = function () {
        alert('hello');
    }

    return {
        publicfunction : function () {
            privatefunction();
        }
    }
})();

As you can see there, a is now an object, with a method publicfunction ( a.publicfunction() ) which calls privatefunction, which only exists inside the closure. You can not call privatefunction directly (i.e. a.privatefunction() ), just publicfunction().

It's a minimal example, but maybe you can see uses to it? We used this to enforce public/private methods.


The example you give is an excellent one. Closures are an abstraction mechanism that allow you to separate concerns very cleanly. Your example is a case of separating instrumentation (counting calls) from semantics (an error-reporting API). Other uses include:

  1. Passing parameterised behaviour into an algorithm (classic higher-order programming):

    function proximity_sort(arr, midpoint) {
        arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; });
    }
    
  2. Simulating object oriented programming:

    function counter() {
        var a = 0;
        return {
            inc: function() { ++a; },
            dec: function() { --a; },
            get: function() { return a; },
            reset: function() { a = 0; }
        }
    }
    
  3. Implementing exotic flow control, such as jQuery's Event handling and AJAX APIs.


JavaScript closures can be used to implement throttle and debounce functionality in your application.

Throttling

Throttling puts a limit on as a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds."

Code:

const throttle = (func, limit) => {
  let isThrottling
  return function() {
    const args = arguments
    const context = this
    if (!isThrottling) {
      func.apply(context, args)
      isThrottling = true
      setTimeout(() => isThrottling = false, limit)
    }
  }
}

Debouncing

Debouncing puts a limit on a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called."

Code:

const debounce = (func, delay) => {
  let debouncing
  return function() {
    const context = this
    const args = arguments
    clearTimeout(debouncing)
    debouncing = setTimeout(() => func.apply(context, args), delay)
  }
}

As you can see closures helped in implementing two beautiful features which every web application should have to provide smooth UI experience functionality.


Yes, that is a good example of a useful closure. The call to warnUser creates the calledCount variable in its scope and returns an anonymous function which is stored in the warnForTamper variable. Because there is still a closure making use of the calledCount variable, it isn't deleted upon the function's exit, so each call to the warnForTamper() will increase the scoped variable and alert the value.

The most common issue I see on Stack Overflow is where someone wants to "delay" use of a variable that is increased upon each loop, but because the variable is scoped then each reference to the variable would be after the loop has ended, resulting in the end state of the variable:

for (var i = 0; i < someVar.length; i++)
    window.setTimeout(function () {
        alert("Value of i was "+i+" when this timer was set" )
    }, 10000);

This would result in every alert showing the same value of i, the value it was increased to when the loop ended. The solution is to create a new closure, a separate scope for the variable. This can be done using an instantly executed anonymous function, which receives the variable and stores its state as an argument:

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () {
            alert("Value of i was " + i + " when this timer was set")
        }, 10000);
    })(i);

In the JavaScript (or any ECMAScript) language, in particular, closures are useful in hiding the implementation of functionality while still revealing the interface.

For example, imagine you are writing a class of date utility methods and you want to allow users to look up weekday names by index, but you don't want them to be able to modify the array of names you use under the hood.

var dateUtil = {
  weekdayShort: (function() {
    var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    return function(x) {
      if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
        throw new Error("invalid weekday number");
      }
      return days[x - 1];
    };
  }())
};

Note that the days array could simply be stored as a property of the dateUtil object, but then it would be visible to users of the script and they could even change it if they wanted, without even needing your source code. However, since it's enclosed by the anonymous function which returns the date lookup function it is only accessible by the lookup function so it is now tamperproof.


There is a section on Practical Closures at the Mozilla Developer Network.