I was source-diving a Backbone.js application recently and noticed the liberal use of _.bindAll(this) calls throughout the code base. Then, in another jQuery-heavy application, I noticed frequent use of the $.proxy() call. In the past, I have certainly been guilty of the former – you know the “What the heck is ‘this’, this time? Nuke it from orbit and just bind all the methods!” But seeing it so often in others’ code made me wonder – are they aware of what’s happening? You probably are, but let’s look anyway:
var Person = function( name ) {
this.name = name;
};
Person.prototype.greet = function() {
return "Oh, hai " + this.name;
};
Person.prototype.sayBye = function() {
return "Get lost, " + this.name;
};
var me = new Person("Jimbabwe");
Inspecting the above instance will show us something similar to this:

Notice that the “greet” and “sayBye” methods appear on the prototype of “Person”.
Now let’s pretend that we’ve gotten terribly frustrated because our “greet” method is being invoked asynchronously (we assigned it as the click event handler on a fictional ‘greet’ button), and we’re consistently seeing “Oh, hai undefined”. In our frustration, we “brute force” the context to be the proper “this” by doing, well, this:
// assuming underscore is present....
var Person = function( name ) {
this.name = name;
_.bindAll( this );
// FYI, an alternative to the above _.bindAll could be:
// _.bindAll( this, "greet", "sayBye");
// args following the context specify method names to bind
};
Person.prototype.greet = function() {
return "Oh, hai " + this.name;
};
Person.prototype.sayBye = function() {
return "Get lost, " + this.name;
};
var me = new Person("Jimbabwe");
Now, when we inspect the “me” instance, we’ll see something like this:

That’s right – using .bind, .bindAll, $.proxy or even plain ES5 Function.prototype.bind() to bind the “this” context results in an instance-level method. This should be obvious, right? Surprisingly enough, many of the people I’ve talked to haven’t stopped to think about this. That sound you hear is the mini-Crockford-angel (or devil, perhaps) on your right shoulder, reminding you that by creating instance-level methods, you’ve erased the gain of having methods on the prototype. If the method stays on the prototype, it’s created once and then shared by future “Person” instances. There is a very real memory and CPU performance loss in wastefully assigning instance members when you don’t need to. Consider this:

All three tests use the same prototype – where “Normal” has no context binding, and the others use underscore and jQuery, respectively, to bind the context of the prototype methods in the constructor functions.
Ok – so we’ve established that explicitly binding the context of a prototype method creates an instance level method, as well as the fact that doing so unnecessarily can result in a serious performance drop – but are there any other potential gotchas? I can think of at least one – stealing a bound method:
var Person = function( name ) {
this.name = name;
_.bindAll( this );
};
Person.prototype.greet = function() {
return "Oh, hai " + this.name;
};
Person.prototype.sayBye = function() {
return "Get lost, " + this.name;
};
var me = new Person("Jimbabwe");
var obj = { name: "Eduardo" };
me.greet.call(obj);
// "Oh, hai Jimbabwe"
I’m going to go ahead and concede that I have no idea why someone, in their right mind, would need to steal the “greet” method from the “me” instance and call it on “obj” – as long as you concede to me that there’s no end to the unpredictability of developers doing crazy nonsensical things after you’ve bequeathed a pristine codebase to them. But the point still stands – it’s important to realize that once you’ve bound the method, it’s bound. The only way around unexpected side effects in the above example would be to call “Person.prototype.greet.call(obj);” – probably not a bad practice in general, should you need to steal methods at some point.
Hold On a Second, Let’s Back Up
This begs the question – why did the developer feel the need to bind the method to begin with? “This” wasn’t what they expected or needed, of course! But why does that happen? When “greet” is invoked on the “me” instance, it’s invoked as a method. The context – “this” – points to the instance. However – what happens when we take that method and assign it as the callback to be invoked when an event occurs? The event will invoke the callback asynchronously – at some point when (in this case) we click the button:
$("#greeter").on("click", me.greet);
When the event occurs, the element will own the context as the callback is invoked. When the function attempts to access “this.name”, it will get an undefined value. Avoiding this error is obviously important, but does it have to be solved by binding all the prototype methods to the instance? No! You can bind at the point of subscribing to the event:
// using $.proxy
$("#greeter").on("click", $.proxy(me.greet, me));
// using _.bind
$("#greeter").on("click", _.bind(me.greet, me));
// using ES5 (or a shim)
$("#greeter").on("click", me.greet.bind(me));
Some eventing libraries provide explicit facilities to let you specify the context, without having to actually pass a bound function. (In fact, Backbone binds the context of your DOM event handlers automatically to the view for you as it wires them up.) Under the hood, many (but not all) of those libraries are typically using call/apply to pass the context to the function as it is invoked.
// postal subscription on a channel
var sub = channel.subscribe("my.topic", callback)
.withContext(something);
// Backbone Events - can pass context as optional 3rd arg
someModel.on("change:firstName", doStuff, this);
It’s a safe assumption that not every method on your instances will be invoked asynchronously, as a handler to an event. So – binding the context on an as-needed basis (as you register event callbacks) will have a much more performance-friendly CPU & memory footprint.
Ok, so:
- Binding prototype methods creates instance level methods? Check.
- Instance level methods are created each time the instance is, and result in decreased performance? Check.
- Stealing bound methods can violate the principle of least surprise? Check.
- It’s better to only bind the context in situations that actually will result in changed context? Check.
Is there anything else we should be aware of? Yes:
// using _.bind on me.greet
$("#greeter").on("click", _.bind(me.greet, me));
// This will not remove the event handler
$("#greeter").off("click", me.greet);
The above example is stating the obvious, I know. But it’s a good reminder that binding the context of a function produces a new function. If you plan to remove the event subscription, you’ll need to either hang on to a reference to the bound function to remove it specifically, use a namespace to separate it from other handlers, or be willing to clear all the events, etc. Also – it’s worth noting that jQuery goes a bit further with $.proxy, so that it’s possible to unbind a bound handler by passing the original function reference as opposed to the bound one. Regardless, though, jQuery’s own documentation still recommends that you use event namespaces.
So – armed with this – may your binding be bind-free….




Pingback: YUI Weekly for February 15th, 2013 - YUI Blog