Sunny doesn't really get what's going on with the nested function () {} business, but the code works fine. So she happily sticks it into a <script type="text/javascript"></script>, changes the HTML ids to match her content, and forgets all about it... until the next month, when her boss says, "Hey, remember that great little show/hide feature you wrote? Marketing wants the same thing for every section on the page."

Now Sunny has to figure out how to make that little snippet reusable. "No problem!" she thinks. "I'll just make it into a function that takes a couple of id parameters so it knows what links are toggling which paragraphs." So she gives that a try:

It works great! The link text changes and the paragraph toggles. "Now all I have to do is wire it up to the click event," thinks Sunny. "I'll get paragraph1 working, and then I'll iterate over the rest of them." So off she goes:

$('a#toggler1').click(toggle('toggler1', 'paragraph1'));

If you've written much JavaScript, you know what's going to happen when she clicks on that link: Exactly nothing. Eventually Sunny figures out her problem: The jQuery click() function, which you use to add a click event handler, takes a function argument. You can't pass it toggle('toggler1', 'paragraph1'). You have to pass the toggle function itself. JavaScript treats functions as first-class objects, and you pass them around just like any other object.

"But I can't pass just toggle—that doesn't have enough information! How am I supposed to pass in the parameters I need?" Sunny protests. She Googles around some more, and she finds out about the magic of closures! As it turns out, if you write a JavaScript function inside another function, the inner function can see all the variables in the outer function. "So that's why you see all these function () {} declarations inside other functions! Maybe I should turn toggler back into one of those." So she tries again:

When Sunny wants a new instance of Toggler, she can instantiate it like this:

var toggler1 = new Toggler('toggle-link-1', 'paragraph-1');

Step 2: Function.prototype.bind (or jQuery.proxy)

So now we have an object, which is fine and dandy, but we still have the same problem Sunny had when she tried passing toggle('toggle-link', 'paragraph'): How do we turn toggler1.toggle into something we can pass into jQuery's click() method? The answer is Function.prototype.bind. It's a new JavaScript feature (introduced in ECMAScript 5) that lets you package up a method on an object instance, together with the instance itself, and turn the whole thing into a first-class function you can use as an event handler. Here's how it works:

That .bind() call is the key to this whole pattern. It's a method on the built-in Function object's prototype. Its superpower is that it lets Sunny specify what she wants this to equal when her method gets called. The this keyword is always supposed to refer to the object that your function is a method of—just like it does in Java or PHP or any number of other languages—but in JavaScript, it doesn't always work that way. For example, if you create a click handler without using .bind() on it, you'll find that this is a reference to the link that got clicked! That's pretty crazy behavior for anyone familiar with object-oriented programming. Fortunately, by using .bind() on your object methods, you can keep the meaning of this sane.

One thing to be aware of is that older browsers don't have Function.prototype.bind available natively. This includes IE8, FF3.6, and all versions of Safari. So for those browsers, you have to provide your own definition of Function.prototype.bind. Mozilla has a handy polyfill you can use. It won't hurt anything in modern browsers, and it'll make .bind() work correctly in older ones.

Alternatively, if you have jQuery 1.4 or higher available, you can use jQuery.proxy in much the same way:

I don't really recommend jQuery.proxy in most cases. It tries to keep track of your bound functions for you, so you can unbind them later even without a reference to your function object, and that can cause problems if you're creating multiple event handlers (say, one for each toggle link on the page, which is Sunny's use case). I do often use it when writing JavaScript for Drupal, though, since Drupal doesn't have Function.prototype.bind available (yet!).

Putting it together

Here's how Sunny could write her toggler code using objects and Function.prototype.bind:

Obviously this isn't the most efficient way to implement a toggle link—there are lots of better ways to do it (jQuery toggle(), for one!). The point here is to illustrate how .bind() lets you write object-oriented JavaScript that respects the this keyword. It's a technique that could eliminate a lot of undocumented anonymous functions if more people knew about it.

I'm especially interested in getting more people in the Drupal community familiar with this pattern, so if you maintain a Drupal module and you want to give this a try, come find me on IRC in #drupal-contribute and I'll be happy to help. I've also proposed a workshop at the Pacific Northwest Drupal Summit where we'll be refactoring JavaScript from the audience. If you're coming to the summit and you have some JavaScript you're not proud of, bring it by for a few small repairs!