“I’m not interested in closure.” – Larry David
Larry wasn’t talking about JavaScript when he uttered these words, but if he had been, I would have to disapprove. Understanding closures is important and is expected of professional-level JavaScript programmers. The proper use of closures adds useful variable and function hiding techniques to a programmer’s repertoire – on the other hand, an inadvertent creation of a closure can in some scenarios lead to a memory leak. In this article, closures will be clearly explained and the useful effects as well as the potential unwanted effects of closures will be examined.
Closure can be a difficult concept to grasp. In my early JavaScript days, I became aware of the concept but struggled to understand it. Eventually, I stumbled upon some decent examples (there are many poor ones out there) and forced myself to study them until closure finally made sense to me. So, I understand both “not getting it” and “getting it”, which in my opinion puts me in a good position to explain closure. If it has been fuzzy or incomprehensible to you until now, this article should put an end to that.
We’ll be looking at four examples of closure. The first two are very similar to one another and both of these are stripped of any extraneous code. The third example is somewhat more complex because I am trying to use closure to demonstrate a real-world analog of something that is like closure. I tried to keep this example as simple as possible, but there is some risk that this additional complexity might dirty the waters and obscure the closure within. If you find Example 3 confusing, ignore it and consider only on Examples 1 and 2, which illustrate the same basic principle as Example 3. Example 4, while important, can also be temporarily ignored if you are just trying to come to grips with closure – perhaps you can come back to Example 4 at another time if it does not make sense at first. Any or all of these examples can be run from the following links: Example 1, Example 2, Example 3, Example 4. It may or may not be helpful to see these small demos before walking through the code. The same links will be also be provided at the end of the article.
So, what is a closure? Closure is automatically enabled when one function is defined inside another. In fact, when you see the word “closure”, it might be best to think of the word “enclosure” instead. Why? Because “enclosure” is a more appropriate word for what closure is. If a function is defined inside of an enclosing function, then that inner function enjoys not only it’s own scope and the global scope, but also the scope of its enclosing function. These are standard JavaScript scoping rules, but there is one more point to understand in order to grasp the idea of closure. During run time, even if the outer enclosing function has executed and is no longer in context, if you have a reference to the inner function on hand, the inner function still knows about the scope of the enclosing function that invoked it. The inner function retains access to the variables and any other functions of the enclosing function. It is important to remember that it is not the state of those variables at the time of the call that is preserved, it is the reference to those variables. This is an important distinction that will be explored in Example 4, but for now we should focus on the most basic explanation of closure.
The example below should clarify the basic explanation of closure given above. The actual JavaScript code that forms the closure consists of only a handful of lines. However, the entire example is not very large and I think it will make the explanation easier to understand if both the closure code and the supporting HTML with other code is shown. (Note: Normally, good practice is to separate JavaScript from HTML, but for an example like this it is better to include them together.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<!DOCTYPE html> <html> <head> <title>Closure Example 1</title> <meta charset="utf-8"> <script type="text/javascript"> function makeGreeting (who) { var greeting = "Hello "; function GreetWhomever() { return greeting + who; } return GreetWhomever; } // the global convenience variables that hold the functions having closures var greetWorld = makeGreeting("World!"); var greetJohn = makeGreeting("John"); </script> </head> <body> <h3>Closure Example 1 - A Very Simple Example</h3> <br /> <input type="button" value="Say hello to the world" onclick="alert(greetWorld())"/> <input type="button" value="Say hello John" onclick="alert(greetJohn())"/> </body> </html> |
In Example 1 above, turn your attention to lines 8 through 16 – you will find there the hallmark of a closure: a function within a function. The enclosing function, “makeGreeting”, has one argument named “who”, one internal variable named “greeting”, and one internal function named “GreetWhomever”. Notice that the GreetWhomever function takes advantage of the scope of it’s enclosing function to utilize both the variable named greeting and the argument named who. These variables don’t belong to the inner GreetWhomever function, but the scoping rules of JavaScript allow the inner function to see the variables and arguments of it’s enclosing function. What we have here are the makings for a closure, but not the closure in action. To see a closure at work, you can run the demo for Example 1. Each button gives a separate greeting: one is “Hello World!”, the other is “Hello John”. Let’s examine the code a little more closely to see why this is so.
Looking at the last line of the makeGreeting function, it can be seen that the definition of the GreetWhomever function is being returned. Note that it is not the result of the function, but a reference to the function itself that is being returned. So, when the global variables “greetWorld” and “greetJohn” are being initialized, they are actually receiving a reference to the GreetWhomever function. This is borne out by the fact that in the onclick handlers of the two buttons, it can be seen that parenthesis has been used in conjunction with the variable names in order to invoke them as functions. Ok, so that is understandable, but what of the closure magic? Look again at the initializion of the greetWorld and greetJohn variables. In each case, the enclosing makeGreeting function is being called, but a different greeting recipient is being passed in each case. The value of the greeting recipient is therefore present in the “who” argument of the makeGreeting function. Upon examining the inner GreetWhomever function, it can be seen that this “who” argument as well as the value of the “greeting” variable of the makeGreeting function are being used by greetWhomever. We already knew that it could do so, because an inner function enjoys the scope of it’s enclosing function. The really interesting thing is, once the greetWhomever function has been returned and stored in the two global variables named greetWorld and greetJohn, the makeGreeting function has already been executed and is “gone”. You’d think it has gone out of scope – but it hasn’t, because it is a closure for the inner function. The inner function still has access to the variables of the outer enclosing function, even though the outer function has already executed. This is closure at work.
Now let’s take a look at Example 2. I will only show the code for the JavaScript of this lesson. The HTML for this example is the same as in Example 1. In fact, the JavaScript is almost the same as well, though not quite. Example 2 exists for two reasons. First, it repeats the lesson that was exposed in Example 1, but in a slightly different way – hopefully driving the lesson home. The other reason is that the syntax employed in Example 2 is a lot more common than the syntax employed in the previous example.
1 2 3 4 5 6 7 |
function makeGreeting (who) { var greeting = "Hello "; return function () { return greeting + who; }; } |
In Example 2 above, the inner function is an anonymous function – it has no name. This is a syntax that will be much more frequently encountered in actual JavaScript code than the syntax employed in Example 1. Nonetheless, the code in this example works exactly the same as the code does in that example. The inner function still utilizes the enclosing function’s variables (i.e. argument “who” and variable “greeting”) after the enclosing function has executed and is “gone”. If you run the demo for this example, you will see that it behaves exactly the same as the demo for Example 1.
My goal for Example 3 was to come up with a real-world analog of closure, and use JavaScript closure to make the example work. I wanted to come up with a real-world analog into the article to help cement what JavaScript closure is. The example I chose was that of a letter from friends or family vacationing in Hawaii (snail mail is not quite dead, though we are getting close). The idea is that the letter itself is enclosed in an envelope. We open the envelope and read the letter, and the letter informs us that there is a also a small picture inside the envelope that we missed when we pulled out the letter. Because of the reference to the picture in the letter, we fish the picture out of the envelope to have a look at it. The parallels to closure may or may not be obvious, but I’ll point them out anyway. The envelope is like the enclosing outer function. The letter inside is like the inner function. The letter refers to a picture that we also discover inside the enclosing envelop. The picture is like the data that belongs to the enclosing function and yet can still be referred to by the letter. For this example, I’ll present the entire HTML and JavaScript that make up the example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
<!DOCTYPE html> <html> <head> <title>Closure Example 3</title> <meta charset="utf-8"> <script type="text/javascript"> // this is the outer envelope function that provides the closure function envelope() { var picHawaiiCoast = new Image(); picHawaiiCoast.src = "hawaii_volcanic_coast.jpg"; // this is the inner function (serving as an object constructor as well) // that directly references its own data - the text of the letter, // and also references the "private" data in the closure - the picture function Letter () { this.text = "Hello everyone!\n\nHaving a wonderful time in Hawaii - hope you all are doing well."; this.text += "\n\nYesterday we took a helicoptor ride and I snapped this neat photo of lava on the coast - check it out."; this.text += "\n\nSee you in one more week!"; this.getEnclosedPhoto = function () { return picHawaiiCoast; }; } return new Letter(); } // the global convenience variable that holds the Letter object, // once the envelope has been opened var theLetter = null; // these are the functions for the buttons running the example function OpenEnvelopeAndReadLetter() { theLetter = envelope(); var letterViewArea = document.getElementById("txtaLetter"); letterViewArea.value = theLetter.text; } function pullPictureOutOfEnvelopeAndLookAtIt() { if (theLetter === null) { alert("You need to open the envelope first."); return; } var pictureViewArea = document.getElementById("imgPicture"); pictureViewArea.src = theLetter.getEnclosedPhoto().src; } // this fails, because the picture image is "private" data, in the closure function naiveAttemptToSeePicture() { try { var pictureViewArea = document.getElementById("imgPicture"); pictureViewArea = picHawaiiCoast; } catch (e){ alert("An error was encountered: \n\n" + e.message); } } </script> </head> <body> <h3>Closure Example 3 - An Attempt at Explanation via a Real-World Analog to Closure</h3> <br /> <input type="button" id="btnLetter" value="Open the envelope and read the letter..." onclick="OpenEnvelopeAndReadLetter()"/> <br /> <textarea id="txtaLetter" rows="10" cols="80"></textarea> <br /> <br /> <input type="button" id="btnPicture" value="Pull the picture out of the envelope and look at it..." onclick="pullPictureOutOfEnvelopeAndLookAtIt()"/> <br /> <img id="imgPicture" /> <br /> <br /> <br /> <br /> <input type="button" id="btnLetter" value="Go ahead and try to access the enclosed picture directly ..." onclick="naiveAttemptToSeePicture()"/> </body> </html> |
In the rather long example above, take a look at lines 9 through 27. It can be seen that this is pretty much more of the same – a function within a function. The enclosing function here is named “envelope”. The inner function is actually a constructor function for an object called “Letter” – but it is still a function and the closure trick still works. In this example, the only variable that the inner function uses from the outer enclosing function is the Image variable, “picHawaiiCoast”. Nevertheless, a closure is a closure and this example functions very similarly to the first two examples.
In one way, this real-world analog of an envelop with a letter and a picture enclosed does not match the reality of JavaScript closures. With the physical objects we can open the envelope and pull the picture out – this is precisely what closures can prevent – direct access to the variables belonging to the outer function. I tried to gloss over this and make the analogy seem close to the way closures work by saying that “we had missed the picture until the reference to it within the letter made it available”. However, it is important to remember that in JavaScript, access to an outer function that is “no longer present”, is granted only through the reference to the inner function at hand. The bottom-most button in the example demonstrates this. Now that you have been exposed to the code for Example 3, it might make sense to run it (see links at top or bottom of article) if you have not already done so.
Earlier in this article, in the paragraph in which closure was defined, I made this comment: “It is important to understand that it is not the state of those variables at the time of the call that is preserved, it is the reference to those variables”. The purpose of the fourth and last example is to help explain what that means. Example 4 provides a UI with two buttons – each button causes console output (accessible in Chrome via Ctrl-Shift-J, in Firefox via Ctrl-Shift-K and in IE via F12 – apologies to Safari and Opera users, I am unfamiliar with those). One button is backed by code using a closure that makes a naive attempt to count from 1 to 3. The other button is backed by code using a closure and an additional level of closure to fix the problem with the naive attempt. If you were to run the examples and press each button in succession (naive, then non-naive) you would see the following output in the console:
1 2 3 4 5 6 7 8 |
Naive attempt to count from 1 to 3 employing a closure: Count = 4 Count = 4 Count = 4 Non-naive attempt to count from 1 to 3 employing closures: Count = 1 Count = 2 Count = 3 |
Examine the code behind each of these buttons below. (The minimal HTML needed to execute the example has been omitted).
Code behind the “Naive Count 1 to 3″ button:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function naiveMakeArrayOfCountingFunctions (countTo) { var count = 0 var countString = "Count = "; var funcArr = []; while (count < countTo) { funcArr[count] = function() { console.log(countString + (count + 1)); } count += 1; }; return funcArr; } function runNaiveCountingFunctions() { console.log("Naive attempt to count from 1 to 3 employing a closure:"); var functionArray = naiveMakeArrayOfCountingFunctions(3); for (var f = 0; f < functionArray.length; ++f) { functionArray[f](); } } |
The “naive” code above fails, outputting three consecutive lines of “Count = 4″, instead of the expected “Count = 1″, “Count = 2″ and “Count = 3″ on three consecutive lines. Why? Because the closure from which each function is referencing variables is the same closure. Furthermore, the state of the count variable in that closure is such that count is equal to 4 when the functions are finally executed. It makes no difference at all that as the individual functions were stuffed into the array, the value of count was 0, 1 and 2 respectively.
Code behind the “Count 1 to 3″ button:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function makeArrayOfCountingFunctions (countTo) { var count = 0 var countString = "Count = "; var funcArr = []; while (count < countTo) { funcArr[count] = function(c) { count += 1; return function (){ console.log(countString + (c + 1)); }; }(count); }; return funcArr; } function runCountingFunctions() { console.log("Non-naive attempt to count from 1 to 3 employing closures:"); var functionArray = makeArrayOfCountingFunctions(3); for (var f = 0; f < functionArray.length; ++f) { functionArray[f](); } } |
The “non-naive” code above succeeds, outputting a count of 1, 2 and 3 as expected. Compare the two sets of code above. The “non-naive” successful code wraps the original inner function in a new function, passing in the value of the outer function’s count variable via an argument. This works, because we have created a new, intermediate closure around each innermost function. Study it and think about it until it makes sense. If it doesn’t click for the moment, that is alright, you will still have made the most important mental leap in understanding closures if you comprehend Examples 1 and 2. You can come back to this later when you stumble upon a closure bug like this and then this example will help you figure it out. Similar problems can crop up when setting up event handlers, so keep that in mind.
So what are closures good for? At the top of the article I promised that we’d delve into some useful features of closures. I’ll cover two reasons here.
- The first reason is that they are a great way of hiding variables and functions – i.e. making them private. Only the inner function has access to this data once the outer function has executed. This mimics the idea of private members in object oriented languages such as C++ and Java, allowing the construction of objects with both private data and private function members. Example 3 is a case in point, although a more useful pattern for creating a reusable object with private members would result if the enclosing function returned the inner “constructor” function instead of using the inner function to create a new object.
- A second reason I will point out, though not discuss in detail, is that when using closures to define member variables for objects, no “this” reference is involved. That is different than the syntax necessary when defining a constructor function with instance variables and methods. That difference is important when using object methods in conjunction with things like event handlers, which reset the “this pointer” and can cause bugs in code when a method of an object is passes as the callback for an event handler. That particular problem is non-existent when a closure was used to create member variables and functions for an object.
Are there any other problems that can occur if closures are not understood or go unrecognized? In addition to the type of bug that Example 4 embodies, in some browsers and some scenarios, the formation of a closure can result in a memory leak. This problem can often occur in conjunction with the establishment of an inadvertent circular reference due to the formation of a closure during event callback creation. I am not going to attempt to explain this in detail here – it is a topic for an entire other article. I will however, point you to this excellent article on JavaScript memory leaks, located on the IBM developerWorks site: Memory leak patterns in JavaScript.
Well, it’s time to bring this article to a close. I hope that if you were “closure-challenged” (which is not uncommon), this article helped you get some closure on closures. As promised above, here again are the links to the four examples discussed in this article: Example 1, Example 2, Example 3, Example 4.