Closure Shopping

A pun on "clothes"!

Shopping Example

Let's see closures in action in a web page. Suppose we have a page that has an item for sale, say pants, and it has an associated button that increments a counter, updates a database, updates the web page and maybe other things. So, you write some code like this:

function updatePantsDatabase(n) {
    console.log("Pants Database updated with "+n);
}

0 Pants

Here's the HTML code. Note that we haven't learned the <output> and <button> tags yet, but we will soon. The <output> tag is used when we will have text output to the page that is dynamically updated. A <button> is clickable, like a hyperlink, but without a default action that we have to prevent.


And here's the JavaScript code:


The event handler function we've written depends on the global variable pantsClicks. We should generally avoid global variables, so that's not ideal. Nevertheless, the code works fine.

Next, we decide to add additional buttons for shirts, skirts, shoes and more. Of course, we could copy/paste the code above for each of our clothing items, but copy/paste is usually a bad idea. Duplicate code means that if we change our implementation, we have to update all the copies of the original implementation.

Event Handler Maker

But how do we write a generic event handler? We could write a function to make one. While we're at it, we'll make the updatePantsDatabase function more generic, replacing it with an updateDatabase function that takes the clothing item and the counter as arguments.

function clothingClickHandlerMaker(item,outputId) {
    var counter = 0;
    return function () {
         counter++;
         updateDatabase(item,counter);
         $(outputId).html(counter);
         };
}

How do we use the clothingClickHandlerMaker? Here are two examples, where we invoke the clothingClickHandlerMaker function to return a closure that we then attach as the click handler.

0 Shirts

0 Skirts

Here's the JavaScript code:


This is a complicated example, so let's review:

  1. The function clothingClickHandlerMaker takes two strings (a clothing item and the CSS selector for the output element) and it returns a closure.
  2. That function has a long name, so I created a shorthand: chm
  3. We invoke chm several times, and each time it returns a new closure over different variable values.
  4. We attach the closure as the event handler for the button.
  5. Each closure works independently, even though they use the same variable names

We can create as many click handlers as we want, without needing any global variables!

Closure Variables

Let's look again at the clothingClickHandlerMaker:

function clothingClickHandlerMaker(item,outputId) {
    var counter = 0;
    return function () {
         counter++;
         updateDatabase(item,counter);
         $(outputId).html(counter);
         };
}

What variables does it close over? It closes over every variable that is not defined within the function. Here there are three:

  1. item
  2. outputId
  3. counter

The first two closure variables won't change ever, so the JavaScript engine can really just substitute the values as static constants. The counter, however, is interesting, because it's updated by the closure invocation. Each closure basically has its own private counter, that happens to have the same name as the counter in all the other closures, but they are different variables: different counters with different values.