Showing posts with label scope. Show all posts
Showing posts with label scope. Show all posts

Tuesday, 18 March 2008

The Horror of Implicit Globals

This code should cause an error, right?

function doSomething()
{
var x;

x = 10;
y = 20;

alert('x = ' + x);
alert('y = ' + y);
}
Well, you'd think so, wouldn't you? (There's no declaration for y.) It doesn't, though. It also probably doesn't do what the author intended. Welcome to The Horror of Implicit Globals. The good news is that there's something we can do about it.

Update 2010/03/31: Please see the update at the end of the article, there's good news on this front.
So what did the code really do? Well, in a simple test, it would seem to do what the author intended, in that it shows two alerts:
  • x = 10
  • y = 20
But x and y are completely different; x is a local variable within the function, whereas y is created as a "global variable". Said "global variable" is not declared anywhere at all, it exists purely because it was assigned to by this function. Functions can create global variables willy-nilly with no advance declaration or indeed, with no declaration at all.

This is clearly a Bad Thing, so why would the language designers let it happen? Well, in some sense I think it's a side-effect. To see why we have the possibility of implicit globals, we have to delve into objects and properties.

If you've done any JavaScript stuff with objects, you know that you can assign a property to an object simply by, well, assigning it:
myobject.myprop = 5;
This sets the property myprop on the object myobject, creating a new property if the property didn't exist before. This is simple, it's convenient, and it's part of the power of JavaScript that objects can just acquire properties without any preamble.

But what does this have to do with implicit global variables? Well, you see, JavaScript doesn't have global variables. No, seriously. It has a global object (just the one), and that object has properties. Those properties are what we think of as global (or page-scope) variables. You might think that this is a distinction without a difference, but if it were, the code shown at the beginning of this post would fail because y isn't declared. It doesn't fail, because by assigning y a value, we created a property on the global object.

"Now hang on," you're saying, "there's nothing in that code referencing some kind of 'global object'." Ah, but there is. And that brings us to the scope chain.

I've mentioned the scope chain before. The scope chain is how JavaScript resolves unqualified references: In any given execution context (e.g., global code or function), there is a chain of objects that the JavaScript engine looks to when resolving an unqualified reference: It first checks to see if the top object has a property with the given name, and uses that property if it does; if not, it checks the next object in the chain, etc. The global object is always the last object in the chain. If the engine gets all the way down to the global object and we're assigning a value to the unqualified reference, the reference is assigned as a property of the global object. And since properties don't have to be declared in advance, voilá, implicit globals.

We can see this in practice. The JavaScript specification says simply that there is a global object and that it's always the root of the scope chain, but it doesn't say what it is -- which makes sense as JavaScript is a general-purpose language. In browser-based implementations, though, the global object has a name: window. Technically, the symbol window in browser-based JavaScript is a property of the global object that refers to the object itself. I mention this not only because it's useful to know, but because it lets us prove to ourselves that "global variables" are really properties of the global object. Let's add a line to our code from above:
function doSomething()
{
var x;

x = 10;
y = 20;

alert('x = ' + x);
alert('y = ' + y);
alert('window.y = ' + window.y);
}
This starts out by showing the same two alerts we had before:
  • x = 10
  • y = 20
...and then it shows a third:
  • window.y = 20
...because y and window.y both refer to the same property of the same object, the global object.

All of this holds true even if we do declare y at global scope:
var y;
function doSomething()
{
var x;

x = 10;
y = 20;

alert('x = ' + x);
alert('y = ' + y);
alert('window.y = ' + window.y);
}
This shows the same three alerts shown earlier. (There is a very slight technical difference between declared and undeclared globals that relates to the delete statement, but the distinction isn't important here, it's just a flag on the property.)

Now, some readers will be thinking "Cool! This means I don't have to have 'var' statements for my globals! I can save a bit of space on the downloaded script files!" Well, true, you could. It's an awfully bad idea, though. Not only would it be a bit unfriendly to anyone else trying to read your script (I suppose you could address that somewhat with comments that get stripped out before download), but it would also mean you couldn't use any lint tools, and you really, really want to. Because the ramification of all of this is that a simple typo, perhaps:
thigny = 10;
instead of
thingy = 10;
can create a new global variable in your page, introducing a bug that's awfully hard to find. Fortunately, though, people have created various tools to do lint checking on JavaScript, tools that can find that error for you before you even get to the testing stage, much less production.

And so there we are, the horror of implicit globals -- and the relief of knowing that we have a defense against them!

Update 2010/03/31: Great news for anyone who's been hit by the Horror of Implicit Globals. The new ECMAScript 5th edition specification is out, and it introduces "strict mode." One of the (several) things strict mode does is prevent the very thing this article warns about: Implicit globals. If we were using strict mode, the function at the beginning of this page would have a syntax error rather than a very subtle bug. Result!

Monday, 17 March 2008

When you absolutely, positively need new scope

Just a quick one today, one that in many ways is a solution in search of a problem... ;-)

As you probably know, in most of the languages with vaguely C-like syntax (C, C++, Java, C#, ...), a new block introduces new scope. E.g., this Java code:

String myJavaMethod()
{
String s;

s = "outer string";

{
String s;

s = "inner string";

// (Presumably do something with 's' in here)
}

return s;
}
...while strange, is perfectly valid. It returns a String with the text "outer string". The s variable declared within the inner block is scoped only to the inner block.

A similar-looking JavaScript function has a completely different result:
function myJavaScriptMethod()
{
var s;

s = "outer string";

{
var s;

s = "inner string";

// (Presumably do something with 's' in here)
}

return s;
}
It's still valid, but it returns the string "inner string" rather than "outer string". Blocks do not introduce new scope in JavaScript, only functions do that. (If you're thinking that the second var declaration should be an error, well, I agree -- but it isn't, details here.)

But what if you absolutely, positively need new scope within a function? It's actually pretty easy to achieve; just use a closure. If I really needed my JavaScript function above to behave like the Java version, I could rewrite it like this:
function myJavaScriptMethodUpdated()
{
var s;

s = "outer string";

(function()
{
var s;

s = "inner string";

// (Presumably do something with 's' in here)
})();

return s;
}
Looks weird, eh? What I've done is create an anonymous inline function and then immediately execute it. Since it's a closure (all JavaScript functions are closures), it has access to all of the arguments and variables defined in its containing function except for the ones it's masked by declaring its own (which it's done with s).

Naturally, as this is defining and calling a function, there's a performance aspect although setting up a function call should be fairly quick in any decent JavaScript implementation -- and again, you're only doing this when you absolutely, positively need new scope, right?

So, okay, how is this useful? Well, as I say, this may well be a solution in search of a problem. It mostly gave me an excuse to highlight the fact that blocks don't introduce new scope in JavaScript. And frankly, in most cases if you need to set up new scope within a function like that, it probably means you haven't broken things up into small enough pieces; if you do that, you'll probably find that you don't absolutely, positively need new scope because your pieces are small enough that things are scoped properly.

That said, though, think in terms of sandboxing and namespacing -- if you wrap an entire external library in a closure and then execute that closure, any globally-declared vars in that library become local variables within the closure and can't conflict with others defined at global scope. So there may be something useful there, although it's far from a real sandboxing or namespacing solution...

Saturday, 15 March 2008

Closures by example

In an earlier post, I promised a follow-up with a few examples of closures. Before we get to the examples, a quick note: To avoid cluttering things up with browser-specific stuff, I'm using the Event.observe() method from Prototype. Event.observe() hooks up an event handler, allowing for differences between browser implementations (see the link for more detail).

I have to say that I found this post to be a real challenge, and it took me a while to figure out why: I kept trying to boil things down to their essence, and the fact is that if you do that, you end up with a single example, one that demonstrates that a closure function has access to intrinsic data. And let's face it, that's not very interesting. :-)

So rather than boil things down, I'll give a few examples of where closures frequently get used, even though they all pretty much demonstrate the same fundamental point (about the functions having intrinsic data).

Okay, to the examples:

  1. A Simple Bound Event Handler
  2. Enduring References
  3. Enduring References to What
  4. Private Properties
  5. Callbacks
  6. The Inadvertent Closure (an anti-pattern)
  7. Your Examples
#1: A Simple Bound Event Handler

One of the most common uses of closures is to bind a function and some data to an event handler:
function wireUpMessage(element, msg)
{
Event.observe(
element,
'click',
function()
{
alert(msg);
}

);
}
This wireUpMessage function creates a closure (the bit in bold) and hooks it up to the "click" event of the given element, having it show the given message. The closure keeps a reference to the arguments and variables in scope where it was defined, so it has access to the msg argument we passed the wireUpMessage function, even though that function has returned.

Assuming we have a button with the ID "btnSayHey", we can use this as follows:
wireUpMessage('btnSayHey', 'Hey there');
Try it out:



#2: Enduring References

You could easily get the idea from the previous example that the closure we created somehow had the text "Hey there" bound into it literally. That's not true. It's the reference to the context containing the msg argument that's bound to the closure, not the value of that argument. The msg argument's value is evaluated when the closure is executed, not when it's defined. This is important, powerful, and frequently misunderstood. ;-)

Consider this:
function setupCounterButtons(startBtnName, showBtnName, stopBtnName)
{
var counter;
var intid;

counter = 0;
intid = undefined;

function startCounter()
{
stopCounter();
counter = 0;
intid = window.setInterval(function() { ++counter; }, 200);
}
function stopCounter()
{
if (intid !== undefined)
{
window.clearInterval(intid);
intid = undefined;
}
}
function showCounter()
{
var msg;

msg = "Counter = " + counter + " (";
if (intid === undefined)
{
msg += "not ";
}
msg += "running)";
alert(msg);
}

Event.observe(
document.getElementById(startBtnName),
'click',
startCounter
);
Event.observe(
document.getElementById(showBtnName),
'click',
showCounter
);
Event.observe(
document.getElementById(stopBtnName),
'click',
stopCounter
);
}
This function has the local variables counter and intid, three named functions (which are closures), and a fourth anonymous closure we've passed into window.setInterval. The named functions are: startCounter, which starts a 200ms repeating update of the counter local variable; showCounter, which displays the current counter value; and stopCounter, which stops the 200ms update. It hooks these functions up to the buttons whose names we pass into the function. So if we hook up the buttons 'btnStartCounter1', 'btnShowCounter1', 'btnStopCounter1' with this code:
setupCounterButtons('btnStartCounter1', 'btnShowCounter1', 'btnStopCounter1');
...we get to try it out:



This demonstrates two important things: Firstly, the closures have an ongoing reference to the counter variable, not its literal value where they're defined. Secondly, all of the closures are referencing the same context: When startCounter sets the counter and intid values, showCounter sees those changes; when the closure we've enabled via window.setInterval updates counter, we see that update. All closures defined in the same context share access to that same context.

#3: Enduring References to What?

Look again at the previous example and think for a moment about what it is that the closures have access to, which endures even after the setup function has completed. Is it something unique attached to the setup function? Well, if that were true, what would happen if I called the function again and hooked it up to different buttons; would those buttons control and access the same counter that the first set of buttons do? If your impulse is to say "yes," consider that counter is a local variable within the function. Local variables aren't specific to the function for all eternity, right? They only relate to a specific time you've called that function. So if we call it again...yup, that's it, we get a new context, and the closures within that context access that new context, not the previous one.

And so if we hook up a new set of buttons:
setupCounterButtons('btnStartCounter2', 'btnShowCounter2', 'btnStopCounter2');
We get a second counter. Try it out and see whether there's any interaction between the counter controlled by these buttons:



...and the one controlled by the buttons in the previous example.

Right, there isn't any, because they're referencing different counters.

#4: Private Properties

Lots of JavaScript apps these days make extensive use of object orientation. One key OOP principle is information hiding. There are several good reasons for information hiding. One example is to defend against an object instance having an invalid state. Frequently this is done by having private data members and only allowing access to them via accessor methods that can prevent invalid values. Since all properties of JavaScript objects are public, how can we have private data members? The answer, of course, is to use closures, much as we did with the counters above. (Crockford is probably the first to document how you can do this, here.)

Here's an example, a Circle class that ensures that its radius is never allowed to become negative:
function Circle(radius)
{
this.setRadius = function(r)
{
if (r < 0)
{
throw "Radius cannot be less than zero.";
}
radius = r;
};
this.getRadius = function()
{
return radius;
};

this.setRadius(radius);
}
Note that we don't have a "radius" property on this object at all. This code:
var c;
c = new Circle(10);
alert("Radius: " + c.radius); // undefined!!
Shows "Radius: undefined" because the property simply doesn't exist. Try it:



Instead, the setRadius and getRadius methods of the object are closures, both of which have a reference to the context in which they were defined, and they share that context as they were defined in the same scope. So rather than having a "radius" property, they simply use the radius parameter given to the constructor, which they keep a reference to even after the constructor has returned. Consequently, this code works just fine:
var c;
c = new Circle(10);
alert("Radius before update: " + c.getRadius());
c.setRadius(20);
alert("Radius after update: " + c.getRadius());
Try it:



(I should mention that there is a downside to this. When you do this, all Circle objects [for example] have their own copies of the setRadius and getRadius functions, rather than sharing copies on an underlying Circle.prototype object. That's a whole different topic, though.)

#5: Callbacks

Closures get used as callbacks a lot. Of course, event handlers are callbacks and so we've already talked about this, but it's useful to remember non-event-handler callbacks.

One very common example is container objects that offer a method (usually called "each" or "forEach") that will call a callback once for each contained object. Prototype provides this (Enumerable.each) on arrays and several other objects; Dojo has something similar (dojo.forEach); JavaScript 1.6 defines this for arrays (Array.forEach). So if we have an array (say) of Person objects, we can act on each element like this (using Prototype syntax):
personArray.each(
function(person)
{
// Do something with the 'person' object
}
);
Suppose we wanted to build a sublist of only the people who are 65 and over:
var sixtyFivePlus;
sixtyFivePlus = [];
personList.each(
function(person)
{
if (person.age >= 65)
{
sixtyFivePlus.push(person);
}
}
);
That uses a closure to add each 65-and-over person to the sixtyFivePlus array.

In practice, closures are used like this in modern JavaScript all over the place.

#6: The Inadvertent Closure (an anti-pattern)

In Example #1, I said that a very common use of closures was to bind a function and some data to an event handler. Unfortunately, while it may literally be true that that's a very common use, I suspect many times it's not the intent of the programmer creating the closure. I suspect much of the time, the programmer just wanted to bind the function, not any data, to the event handler, but didn't realize they were creating a closure and binding data as well.

Unless a page author is using DOM Level 0 event handling (e.g., onclick attributes in the HTML markup), usually there's a setup function called on page load that hooks up event handlers to the buttons and such using some analog of the Event.observe function I've been using in this post. Sometimes those setup functions are dealing with large data sets, perhaps a big JSON or XML document retrieved via an XMLHttpRequest query, referencing that data with local variables. Then the event handlers are defined within the setup function, which means they're closures, which means...right, they keep a reference to the setup function's context, and so the large data set is retained in memory.

Now, if that's on purpose -- the page is referring back to it periodically, etc. -- that's fine. But if the data set was just to be used for setup, it's a waste of memory. I call this the "Inadvertent Closure" anti-pattern.

Here's an example:
function mySetup()
{
var setupData;
var n;

// Set 'setupData' to some large amount of data used only for setup;
// the below is just a contrived array.
setupData = [];
for (n = 0; n < 1000; ++n)
{
setupData[n] = "Item " + n;
}

// (Presumably use the setup data for something here)

// Hook up some event handlers
Event.observe(
'someButton',
'click',
function()
{
// Do something interesting
}
);
Event.observe(
'someOtherButton',
'click',
function()
{
// Do something else interesting
}
);
// (Etc.)
}
Here, a bunch of setup data is allocated and referenced via the setupData array, and then we hook up a couple of event handlers that don't need a reference to the setupData array.

Well, they may not need it, but they have it, which means that all of that data is sitting around eating up memory unnecessarily.

The good news is that it's easy to fix. There are at least two ways to fix it; the way I don't like, and the way I like. ;-)

The way I don't like: Just "null out" the big data set when you're done with it; in our example, we'd just add this line to the end of the mySetup function:
setupData = undefined;
Personally, though, I prefer modularity: Break out the bit that needs to deal with the big data set into its own function, and the setup of the event handlers in their own function:
function myBetterSetup()
{
doTheBigDataThing();
setupEventHandlers();
}
function doTheBigDataThing()
{
var setupData;
var n;

// Set 'setupData' to some large amount of data used only for setup;
// the below is just a contrived array.
setupData = [];
for (n = 0; n < 1000; ++n)
{
setupData[n] = "Item " + n;
}

// (Presumably use the setup data for something here)
}
function setupEventHandlers()
{
Event.observe(
'someButton',
'click',
function()
{
// Do something interesting
}
);
Event.observe(
'someOtherButton',
'click',
function()
{
// Do something else interesting
}
);
// (Etc.)
}
This give us a clear separation of what we're doing, and as a nice side-effect, prevents the closures from keeping our data set around unnecessarily.

At this point, a couple of you might be thinking "OMG! But that means any time I'm dealing with a big temporary data set, I need to be sure no closures are defined within that context! What if I want to act on the data set with an iteration function like in Example #5?!" Don't worry. Remember that the context is kept around because it has a reference from the closure; when the closure is released and cleaned up by the garbage collector, the context is also released and can be cleaned up by the GC. This only matters if you're keeping an enduring reference to the closure, as in the case of event handlers.

#7 and on: Your Examples!

I've tried to give some overview of closures based on examples of usage, and I hope it's been useful, but I've really only scratched the surface here; what are your examples? Post away!

Friday, 29 February 2008

Closures are not complicated

Note December 2010: The terminology I attribute to the ECMAScript spec below was from the then-current 3rd edition. The current 5th edition spec (there was no 4th edition) uses different terminology. At some point I'll get around to updating...)

Closures seem to frighten people a bit. Partially I suspect this is down to the academic nature of the term "closure". It sounds like something Californians look to achieve, not something to help you write software. (Disclosure: I mostly grew up in San Francisco, so I'm allowed to poke fun at my fellow Californians. Don't Try This At Home.) I suspect it's also because if you don't know the rules for them, they seem mysterious, and the mysterious is often frightening.

First off, what is a closure? I'll leave a thorough definition to my academic betters, but let's put it this way for my fellow plodders and I: A closure is a function with data intrinsically bound to it.

Consider this code:

function updateDisplay(panel, contentId)
{
var url;

url = 'getcontent?id=' + contentId;
jsonRequest(
url,
function(resp)
{
if (resp.err)
{
panel.addClassName('error');
panel.update(
'Error retrieving content ID '
+ contentId
+ ' from "'
+ url
+ '", error: '
+ resp.err);
}
else
{
panel.removeClassName('error');
panel.update(resp.json.content);
}
}
);
}

This updates a panel element based on the results of a call to retrieve some JSON data. The call to the jsonRequest function accepts two parameters: The URL that will return the JSON data, and a callback function to trigger when the request completes (one way or the other). If the data was returned successfully, the callback sets the content of the panel from the JSON data and makes sure that the "error" CSS class is not set on the element; if there's an error, it shows details about the error and sets the "error" CSS class. (In this example, we happen to be using Prototype to extend our panel element with the nifty class name and update methods, but that's as much to keep the example simple as anything else.)

The callback above is an example of a closure: A function with data bound to it, in this case the panel and contentId arguments we passed into the updateDisplay function, and also updateDisplay's url local variable. It's useful to have this information bound to the callback, because the jsonRequest function doesn't know anything about panel or contentId, it just knows about triggering the callback — but the callback has the information it needs to do its job.

Magic? Nah. I can't speak for closures in other languages, but there's nothing complicated about closures in JavaScript. Seriously. They're dead easy. You need to know, say, three things and you're good to go. Well, four things, but that's only because someone has been misinforming you. Here's a quick list of those four things, after which we'll delve in a bit deeper, and then I'll tell you something at the end that will surprise you for three seconds before you go "Oh, of course":

  1. In JavaScript, everything is a data structure, even functions, and — critically — even the context in which functions run. One aspect of that context is a "call object" (that's Flanagan's term, the ECMA specification uses "activation object" — I'll use "call object" because I'm lazy and it's less typing I find it clearer).
  2. JavaScript variable names are resolved on the basis of a "scope chain", which includes (among other things) the global object and all of the current call objects in scope.
  3. Functions in JavaScript are lexically scoped — for the plodders like me out there, that means that the things a function can access (the things "in scope" for it) are determined by the context in which the function is defined, not the context in which it's executed.
  4. Closures do not create memory leaks. Someone probably told you that they did at some point (perhaps they thought that's what Microsoft was trying to say here).
Okay, let's see how those things come together to make closures easy.

#1: Everything is a object

When we call a JavaScript function, the context of that call to the function — the parameters we've used, the variables within the function itself — are part of an object called the call object (or, again, "activation object" in ECMA parlance). The interpreter creates a call object for this particular execution of the function and sets some properties on that call object before passing it into the function's code. The properties are:

  1. A property called arguments which is an array (of sorts, in most implementations it's not actually an Array object) of the actual arguments we called the function with, plus a callee property which is a reference to the function being called.
  2. A property for each of the arguments defined by the function declaration. The values of these properties are set to the values passed into the function. If any arguments weren't specified (because JavaScript lets you call functions with however many arguments you want, regardless of the definition), properties for any missing arguments are still created on the call object — with the value undefined.
  3. A property for every declared variable within the function (e.g., every "var" statement). (These start out with the value undefined.)

Let's look again at selected bits of the updateDisplay function from earlier:

function updateDisplay(panel, contentId)
{
var url;

// ...
}

And let's assume we call it with a reference to a 'leftPanel' div and a contentId of 123:

updateDisplay(leftPanel, 123);

That creates a call object for this execution of updateDisplay that essentially looks like this:

call.arguments = [leftPanel, 123]
call.arguments.callee = updateDisplay
call.panel = leftPanel
call.contentId = 123
call.url = undefined

This object is then used within the body of the function when the code uses the arguments panel or contentId, or the local variable url, etc.

"But wait," you say. "I don't refer to an object when I use the arguments or variables in my function, I just use their names." Indeed — the use of the call object is implicit. How do we end up using the call object when we just write "contentId" (for instance)? Because once the call object is created, it's put at the top of the scope chain for the duration of the function call. Which takes us nicely to...

#2: Variable names are resolved using a "scope chain"

If you've written JavaScript in a browser environment, you've probably used the global document object, and perhaps the global navigator object as well. Here's the thing: Those aren't global objects. Those are properties of a global object — in fact, of the global object. The document and navigator properties are set up for you by the browser, but they're just properties of an object.

So how do you get away with just giving the property name, rather than giving the object name as well? Because of the scope chain, an ordered series (indeed, a chain) of objects. When the JavaScript interpreter sees an unqualified variable reference, it checks the top object on the scope chain to see if it has a property by that name: If so, it gets used; if not, the interpreter checks the next object down the chain. The global object is the bottom of the chain, so if you just type document.writeln("Blah blah blah"), eventually the document property is found on the global object and used.

(The global object is an abstract entity in the generic JavaScript definition, but in the specific case of a web browser you know it by another name: window. In browsers, the window object is the global object; it just also has a property, "window", that refers to itself.)

So quick: Within a function, how do variable names get resolved? Right! When the function is being executed, the call object with all those nifty properties for the function's arguments and variables is put at the top of the scope chain. So during our call to updateDisplay from earlier, the call object for the call is at the top of the scope chain, followed by the global object, like this:

Image

When the interpreter sees a variable reference, say contentId, it looks on the call object: If there's a contentId property on the call object, it gets used; otherwise, the interpreter looks at the next object in the scope chain, which in this case is the global object.

(There's more to know about the scope chain than I've described here; the astute reader will be wondering, for instance, how objects and their instance members come into play, or what the with statement does to things. Alas, we can't tackle everything all at once...)

But how can I know when I'm writing updateDisplay that the scope chain will look like that? I mean, doesn't it depend on who's calling the function? Nope. And that brings us to our next point:

#3: Functions in JavaScript are lexically scoped

Okay, so we get the concept of the call object, which is created when we call a function; and we get the global object, which sits at the bottom of the scope chain to handle globals. But what's this "lexically scoped" thing? It's just a fancy way of saying that a function's scope is determined by where it's defined (e.g., the text defining it; léxis is Greek for "word" or "speech"), not where it's called.

Let's put that another way: When a function is defined, the code defining it is in some kind of context — a function is running, or the page itself is running if you've done the code at the top level. That context has an active scope chain when the function is defined. So when creating the function object, the interpreter creates a property on it (called [[Scope]] in the ECMA spec, but you can't access it directly) with a reference to the active execution context's scope chain. Even when the context goes away (e.g., the function returns), because the function object created by the definition has a reference to the scope chain, the scope chain isn't garbage collected — it's kept alive by the active reference to it from our function object. (Assuming that we've kept a reference to the function object, as we did in our example by passing it into the jsonRequest method; otherwise, the function and the scope chain are both garbage-collected since nothing references them.)

Remember our closure at the beginning of this post? It gets a [[Scope]] property pointing to the scope chain in effect when updateDisplay was called with panel = leftPanel, etc.:

Image

So when we call it, first its scope chain is put in place, then the call object for this particular call to the function is put on top of the scope chain, and the function is executed with this chain:

Image

And there we are, the closure can access panel and all of the other properties of the call object for the call to updateDisplay because they're on the scope chain. They're on the scope chain because that was stuck onto the closure's function object when it was created. No magic. Just objects, the scope chain, and lexical scoping all working together.

#4: Closures don't cause memory leaks

So why do people think closures cause memory leaks? A couple of reasons, I suspect, but chief among them being a bug in an issue with Internet Explorer. IE's DOM objects are not garbage-collected in the same way that JavaScript objects are; instead, IE shows its COM roots by using reference counting, a mechanism that is, unfortunately, prey to issues with circular references. Event handlers can easily end up being circular references, and so in IE it's easy to "leak" the memory associated with a DOM element and its event handler because they're referring to each other. (JavaScript's garbage collector doesn't have an issue with circular references; it works on the "reachability" principle rather than reference counting.) This is an issue with event handlers, rather than closures, but since many event handlers are written as closures, people associate it with closures. Fortunately, it's not that hard to kick IE into shape (in this particular way); Crockford talks about the problem and its solution here and many toolkits [like Prototype] will do this for you if you ask them nicely.

Lest I be accused of Microsoft-bashing, I should point out that IE is not the only browser that sometimes loses track of things; it's just by far the worst. Firefox 2 has a bad habit of leaking a bit of memory on XMLHttpRequest calls, which also frequently involve closures. The good news there is that Firefox 3 beta 3 is looking awfully good indeed on this front.

Separate from browser issues, though, if you're not really clear on how closures work, particularly with regard to the scope chain, you'll miss the fact that a closure keeps a reference to all of the variables and arguments in scope where it's created, not just the ones it uses; and so if you have (say) a massive temporary array allocated in that scope that the closure doesn't use, you might be tempted to say that the closure is causing the array's memory to leak. (The answer there is simple: Clear the array's variable when you're done with it.)

In Conclusion

There are lots of nifty things you can do with closures. I'll post a follow-up in a couple of days, "Closures By Example", demonstrating a few of them and just generally walking through some seemingly-complicated examples. But until then, I'll just reiterate my theme: Closures in JavaScript are not complicated. They're powerful, but if you understand that 1. Everything is a data structure, 2. Variables — I should probably call them unqualified references — are resolved according to a scope chain, and 3. The scope chain for a function is defined by where the function is defined lexically, you'll be golden.

Oh! I said I'd tell you something at the end that would surprise you for about three seconds before you said "Oh, of course." Here it is:

All JavaScript functions are closures.

Happy coding!