One of the most important tricks an ECMAScript coder can learn is how to properly create ‘object’ with prototypes. A second-place runner up is the use of closures. Closures come from JavaScript’s secret roots in Scheme. They’re a technique for letting scope ‘linger’ around for functions that are called within a function. I looked for tutorials on closures but couldn’t find any immediately that didn’t basically alert someone’s name, which just doesn’t seem very practical to me. Alerting your name is the boring cousin of “Hello, World.” So let’s look at a practical problem with a need for a solution. Let’s say that you have a prototypical object that happens to enhance HTML links that the user can interact with. Since you’re doing progressive enhancements the link will work as expected on browsers that don’t have JavaScript enabled, but for those spiffy browsers that are progressive (not a political statement), you’re going to attach an onClick event. I’m lazy so the examples below are going to use jQuery event attachment, but longer-form addEventListener, which is wonderful and will make your life more fulfilling.
So when you click on this link you want it to be able to refer to your object so that you can work nicely with other libraries or have multiple instances of the object on the page. The hacky ways to do this might have included adding attributes to the HTML object, doing some sort of global object lookup, or any number of other things I did when I didn’t understand closures. But here’s what you’re going to do:
<html>
<head>
<title>Never Gonna Give You Up, Closures!</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
function MakeItCloserWithClosures()
{
/**
Assigning a variable 'that' to have the value of 'this' creates a reference that maintains scope through closure, so sub-functions/lambdas, can reference that as a variable that is in scope to call functions withint this object
*/
var that = this;
$('.makeMeClosureFriendly').click(function(){that.rickRollTheUser();return false;});
}
MakeItCloserWithClosures.prototype.rickRollTheUser = function(){
document.location.href = 'http://www.youtube.com/watch?v=3HrSN7176XI';
};
/* use jQuery's ready function to initialize the object, which should attach it to the HTML objects. */
$(document).ready(function(){ new MakeItCloserWithClosures(); });
</script>
</head>
<body>
<a class="makeMeClosureFriendly" href="http://www.digg.com/closures-are-easy">
Closures are easy!
</a>
<body>
<html>
There are a number of possible issues with the above code as far as scope is concerned: 1) the new object is not assigned to a variable for future reference (which we’ll pretend is awesome and the best idea ever), and 2) since it isn’t assigned there’s no global variable that we could attach to inside of the click event handler (function). Except that with closures we can use the code’s reference to ‘that’ and it will refer back to the originating object and Rick Roll the user. Closures are the best for handling references back to an object that needs to touch code, but not be global in scope or concern itself with as much interaction with other libraries.
I like to think of closures as ‘scope tunnels’ that can linger on for some time as long as the objects that reference them still exist. In complex web applications being able to reference back to a parent object can save lines of code, confusion and can help call functions that are aware of other variables, details, and settings that exist within a JavaScript/ECMAScript object. Fewer lines of code to debug is a big win, and fewer lines of code to maintain is even better. I hope this helps!
Where will you use closures today? See the demo to get Rick Rolled. Please leave questions in the comments.
I don’t understand why it’s of any real value here to assign ‘this’ to ‘that’ when it seems like you could just call ‘this’. Isn’t scope simply maintained within the outer ‘MakeItCloserWithClosures’ function?
Since I don’t use JS frameworks (as yet) I can’t tell if the jQuery syntax is confusing me or if I’m more genuinely missing the point. It could easily be the latter, since I am not fluent in object orientation and very comfortable with procedural flows. This causes me to get confused on a regular basis by stuff that’s IOTTMCO as long as the CO has an OO background.
Eric,
Good question. When you know something you sometimes forget that you’re assuming something. By creating the local variable inside the scope of the object/function you can reference that variable (which happens to be equivalent to ‘this’) inside of functions constructed. I’ll modify this writeup with an update and try to clarify that with a clearer example. JQuery is just assigning the onclick event handler to the function I’m passing it (which in this case doesn’t really care about the event object that would normally be passed).