Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
JavaScript, time to grok closures
This post is part of a series called JavaScript Demystified.

When I wrote about functions in JavaScript I mentioned that functions are more than just a block of code:

Function is a standard data type in JavaScript, an object indeed; you can pass them around and copy them.

Let's take a look at this small sample of a function that creates and returns another function. The returned function accepts one string argument and returns another string repeating the argument a number of times.

function makeRepeater(times){
	return function(text){
		var message = '';
		for (var i=0; i < times; i++) {
			message += text + ' ';
		}
		return message;
	};
}

Let's now write some code that uses that function.

var threeTimes = makeRepeater(3);
var fourTimes = makeRepeater(4);
alert( threeTimes('hi') );
// => 'hi hi hi '
alert( fourTimes('hi') );
// => 'hi hi hi hi '

Nothing spectacular, right? But look closely. The function returned by makeRepeater contains a reference to times, which is a local variable of makeRepeater. When we call threeTimes or fourTimes the makeRepeater call has already returned and times should be out of scope. Or should it?

Extra life for your local scope

You may try to argue and say that the times inside threeTimes is not a reference to the times from makeRepeater, but just a copy of that value. Well, sadly I'll have to prove you wrong. Let's modify our code just a little.

var times;
function makeRepeater(){
	return function(text){
		var message = '';
		for (var i=0; i < times; i++) {
			message += text + ' ';
		}
		return message;
	};
}

times = 3;
var threeTimes = makeRepeater();
times = 4;
var fourTimes = makeRepeater();
alert( threeTimes('hi') );
// => 'hi hi hi hi '  ---> What?!?!
alert( fourTimes('hi') );
// => 'hi hi hi hi '

If it's not clear yet, let me write it down for you. The returned function really keeps a reference to any outside values it will need when invoked. In our original example, it kept a reference to the times local variable at the time it was produced. If we had created other local variables inside makeRepeater they would also become available inside the returned function. In other words, all the scope created during the call to makeRepeater will be preserved for the returned function. This happens when the returned (or inner) function has a reference to anything defined in the parent (or outer) function, i.e. the parent local scope. When this happens, we say that a closure has been created.

Closures can be tricky

It's important to understand the mechanics of closures to avoid subtle bugs in our code. Look at this piece of code, adapted from a real bug I had to fix.

<input type="button" value="Button 1" id="btn1">
<input type="button" value="Button 2" id="btn2">
<input type="button" value="Button 3" id="btn3">

<script type="text/javascript">
	function createEventHandlers(){
		var btn;
		for(var i=1; i <= 3; i++){
			btn = document.getElementById('btn' + i);
			btn.onclick = function(){
				alert('Clicked button #' + i);
			}
		}
	}
	createEventHandlers();
</script>

If you put this code in a page and click the three buttons you will see that all of them will show the message "Clicked button #4". Armed with our understanding of closures we can immediately understand that this bug is being caused by that reference to i used inside the event handler. We can fix that.

function createEventHandlers(){
	var btn;
	for(var i=1; i <= 3; i++){
		btn = document.getElementById('btn' + i);
		btn.onclick = createOneHandler(i);
	}
}

function createOneHandler(number){
	return function() {
		alert('Clicked button #' + number);
	}
}

The above code works because we are not creating functions inside the for loop, hence not producing closures on the same local scope. There is a different set of closures being produced by createOneHandler, but those are not pointing to the same parent scope. Each of these three new closures contain a different scope, created by each call to createOneHandler

Closing thoughts

Closures, of course, are not an exclusive feature of JavaScript. It's a very important trait of functional languages. Even in C#, when we use lambdas, closures are created — many times without us noticing.

The key to properly using closures in our code is to pay attention to locally scoped values from the outer function being used in the body of the inner function. Most of the times this will work as intended by the developer but, when it doesn't, stop and check if more than one closure is sharing the same local scope or if these local values are changing between the inner function creation and its invocation.


Posted 02-23-2009 7:28 AM by sergiopereira

[Advertisement]

Comments

Derick Bailey wrote re: JavaScript, time to grok closures
on 02-23-2009 9:56 AM

you've helped me understand closures much more than I had before. I put together a quick set of tests in c# and am seeing the same behavior for variable scoping that you are showing in javascript. it's good to see that the two languages have the same concept of closures - for 'value' types at least.

thanks, Sergio!

DotNetKicks.com wrote Understand closures with JavaScript
on 02-23-2009 9:59 AM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

sergiopereira wrote re: JavaScript, time to grok closures
on 02-23-2009 10:16 AM

@Derick, glad it helped at least a little. A  good thing in regards to C# is that tools like Resharper will flag some of those situations with an "access to modified closure" warning and even suggest fixes for it.

new ThoughtStream("Derick Bailey"); wrote Closures in C#: Variable Scoping and Value Types vs Reference Types
on 02-23-2009 3:11 PM

I read Sergio’s post on “ Javascript, time to grok closures ” today and it was very enlightening. Overall

Arjan`s World » LINKBLOG for February 23, 2009 wrote Arjan`s World &raquo; LINKBLOG for February 23, 2009
on 02-23-2009 3:22 PM

Pingback from  Arjan`s World    &raquo; LINKBLOG for February 23, 2009

Closures in C#: Variable Scoping and Value Types vs Reference Types | Switch on the Code wrote Closures in C#: Variable Scoping and Value Types vs Reference Types | Switch on the Code
on 02-23-2009 7:10 PM

Pingback from  Closures in C#: Variable Scoping and Value Types vs Reference Types | Switch on the Code

fgantt » Blog Archive » links for 2009-02-23 wrote fgantt &raquo; Blog Archive &raquo; links for 2009-02-23
on 02-23-2009 8:07 PM

Pingback from  fgantt  &raquo; Blog Archive   &raquo; links for 2009-02-23

Reflective Perspective - Chris Alcock » The Morning Brew #293 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #293
on 02-24-2009 3:41 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #293

Timothy wrote re: JavaScript, time to grok closures
on 02-24-2009 9:36 AM

Very informative. Thanks!

Community Blogs wrote JavaScript, inner functions and private members
on 02-24-2009 9:50 AM

This post is part of a series called JavaScript Demystified . In our last installment in this short JavaScript

Christopher Bennage wrote re: JavaScript, time to grok closures
on 02-24-2009 10:32 AM

Your example of a bug resulting from a closure and how to fix it was really good. It communicated the problem very clearly.

Doug Waltman wrote re: JavaScript, time to grok closures
on 02-24-2009 2:39 PM

Thanks for the clear cut explanation, Sergio.  I had seen this behavior before but wasn't able to put it into words like you have.  I definitely understand the mechanics better now.

DotNetShoutout wrote JavaScript, time to grok closures - Sergio Pereira
on 02-24-2009 5:57 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Code Monkey Labs wrote Weekly Web Nuggets #53
on 03-02-2009 1:30 PM

Pick of the week: Paying Down Your Technical Debt General Leveraging ILMerge to Simplify Deployment and Your Users’ Experience : Daniel Cazzulino demonstrates how you can easily combine multiple assemblies into a single assembly. DDD Step By Step : Casey

Sergio Pereira wrote JavaScript, inner functions and private members
on 04-01-2009 8:25 AM

This post is part of a series called JavaScript Demystified . In our last installment in this short JavaScript

Travis wrote re: JavaScript, time to grok closures
on 10-02-2009 6:51 PM

Holy Hell... someone asked me about Closures the other day... I didn't know what they were...

Ridiculous how many problems this solves.

Spent about an hour reading some other docs... that gave me a headache and really didn't elucidate anything... then I found your pages.

Awesome, thanks.

jonny wrote re: JavaScript, time to grok closures
on 02-07-2011 8:52 AM

I don't get this:

"When we call threeTimes or fourTimes the makeRepeater call has already returned and times should be out of scope. Or should it? "

Shouldn't the function makeRepeater return only after the returned function is returned? i.e. they are not pushed onto the stack one after the other and then removed in reverse order?

sergiopereira wrote re: JavaScript, time to grok closures
on 02-07-2011 11:05 AM

@jonny,

No. makeRepeater returns "a function", it does not execute it yet. If it were executing it, you'd see "( )" after the closing "}" of the return statement.

That's the whole point of closures and part of the problems it can create for you when you're not familiar with them yet.

I think if you read the post again or play with the examples in a browser you'll understand it better.

jonny wrote re: JavaScript, time to grok closures
on 02-07-2011 2:36 PM

@sergiopereira: ahh - ok thanks - that makes sense now - returning a "function" and calling it are 2 different things - I am more familiar with C/C++ I missed the fact that it does not have {}()

I did not understand this either:

times = 3;  

var threeTimes = makeRepeater();  

times = 4;  

var fourTimes = makeRepeater();  

alert( threeTimes('hi') );  

// => 'hi hi hi hi '  ---> What?!?!  

alert( fourTimes('hi') );  

// => 'hi hi hi hi '  

The "hi" repeats 4 times since makeRepeater only returns the function and the function is actually called/executed in the alerts

Thanks again!

Perry wrote re: JavaScript, time to grok closures
on 03-05-2011 9:24 PM

just found your article.  extremely helpful.  thanks!

Yoo wrote re: JavaScript, time to grok closures
on 04-05-2011 3:04 AM

forEach also works like createOneHandler.

[1,2,3].forEach(function(i){

btn = document.getElementById('btn' + i);

btn.onclick = function(){

alert('Clicked button #' + i);

}

})

sergiopereira wrote re: JavaScript, time to grok closures
on 04-05-2011 9:27 AM

@Yoo, yes but that's not widely supported yet. It's part of JavaScript 1.6 and most of the users out there are stuck on IE with JavaScript 1.5 (from the year 2000, argh!)

Steve wrote re: JavaScript, time to grok closures
on 07-15-2011 2:55 AM

I was confused so much about closures, and your article really helped, thank you.

I was confused on how

alert( threeTimes('hi') );

worked. 'hi' is not a number, it is a string.

threeTimes is an instance of the object makeRepeater

makeRepeater has a parameter of numeric type

what's going on?

then i read your comment that says makeRepeater returns a function that is not executed yet, but waiting to be executed when the instance is called.

now I get it.

when you call the instance threeTimes, you are actually calling the inner function and passing it the parameter to be used as (text)

that func does its work, and returns the results

the weird concept of closures is how the inner function can have access to parameters and variables of it's parents.

so that's what makes it possible for the inner function to access a property of it's parent object, and use that at the time of execution,

like when you need to find out the name of the instance of the object during runtime in the browser, so you can call a method of the instantiated object to do something, like onClick needs to call a method of the object, but you can't know the name of the instance of the object at runtime, but the inner function can access a property of the object, and that property can hold a references to it using var name = this;

i guess closure means a way to put a function inside a function, close the inner function, and continue with the rest of the original function. and the inner function has access to variables of the parents.

sergiopereira wrote re: JavaScript, time to grok closures
on 07-15-2011 9:22 AM

Steve, you got it right. Glad the article helped.

Deedubb wrote re: JavaScript, time to grok closures
on 08-28-2012 2:35 AM

Thanks for the great article. I just watched Douglas Crockford's lecture from 2006,  titled "Advanced Javascript", and his solution to this same closure problem was almost identical to yours, except he used a self-invoking anonymous function in the loop. If we re-wrote your example that way, it would look like this:

function createEventHandlers(){

   var btn;

   for(var i=1; i <= 3; i++){

       btn = document.getElementById('btn' + i);

       btn.onclick = function(number){

           return function() {

           alert('Clicked button #' + number);

           }

       }(i);

   }

}

kumar wrote re: JavaScript, time to grok closures
on 12-12-2012 12:55 PM

did not understand why do not the var btn refer to the last button object. why are multiple btn variables getting created?? i thought the btn would refer to the last button object!!

sergiopereira wrote re: JavaScript, time to grok closures
on 01-12-2013 6:24 PM

@kumar, the btn var does end the process with a reference to the last button, that's not a problem here. The problem is the value of "i", it also contains the last value form the loop, and a reference to "i" is kept inside the event handler function and displayed in the alert message when that function gets invoked.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)