A List Apart

Menu

Getting Out of Binding Situations in JavaScript

Issue № 262

Getting Out of Binding Situations in JavaScript

by Published in JavaScript54 Comments

Most developers don’t know about—or don’t care enough about—binding in JavaScript. Yet this single issue is responsible for a sizeable portion of the questions on most JavaScript-related support channels, and thousands—if not millions—of hairs being tortured away from developer heads every single day. Yet with a little attention to this oft-overlooked subject, you can avoid wasting your time, energy, and patience and move on to more powerful, efficient scripting.

Why should we care about binding?

Almost no major object-oriented programming (OOP) languages force you to consider binding. That is, they don’t require you to explicitly qualify access to the current object’s members (methods and properties) with a reference such as this or self. If you’re calling a method on no particular object, you’re usually calling it on the current object. The same goes when you’re passing a method around for later invocation: it will retain its current object. In short, for most OOP languages, binding is implicit. This is true in Java, C#, Ruby, Delphi, and C++, to name but a few.

PHP and JavaScript do require you to explicitly state which object you’re accessing, even if it’s the current one. (And that is about as far as I’m willing to put PHP and JavaScript in the same basket.)

Of course, neither PHP nor JavaScript are actually object-oriented in the traditional sense. In the case of PHP, object support was added, rather slapdash, as an afterthought; even in PHP5, functions are not first-order values, and many OOP features are lackluster.  JavaScript is very dynamic and relies on “prototypal inheritance,” which is a significantly different paradigm than class-based inheritance. Such distinctions do not immediately relate to binding issues, but demonstrate that traditional object-related syntaxes and behaviors were of little importance to the designers of JavaScript.

In JavaScript, binding is always explicit, and can easily be lost, so a method using this will not refer to the proper object in all situations, unless you force it to. Overall, binding in JavaScript is not a difficult concept, but it is far too often ignored or glossed over by JavaScripters, which leads to confusion.

Let’s step in it

Consider the following, innocuous-looking examples, and how their actual behavior can seem unpredictable.

var john = {
  name: 'John',
  greet: function(person) {
    alert("Hi " + person + ", my name is " + name);
  }
};john.greet("Mark");
// => "Hi Mark, my name is " 

Okay, that’s weird. Where did the name go?  Well, we were guilty of a binding assumption here: our method just refers to name, which JavaScript will look for in the several valid levels of variables, ending up with the properties of the window object. Of course our window does have a name property, but it’s empty by default, so no name shows up.

Let’s try it out:

name = 'Ray'; // Or explictly: window.name = 'Ray';
var john = {
  name: 'John',
  greet: function(person) {
    alert("Hi " + person + ", my name is " + name);
  }
};john.greet("Mark");
// => "Hi Mark, my name is Ray" 

Well, that’s just dandy, but useless. What we want is our object’s name property, not the one in window!  Here is where explicit binding is important:

var john = {
  name: 'John',
  greet: function(person) {
    alert("Hi " + person + ", my name is " + this.name);
  }
};john.greet("Mark");
// => "Hi Mark, my name is John" 

Notice how we prefix our reference to name with the keyword this: that’s explicit binding. And indeed it works!  Or does it? (Line wraps marked » —Ed.)

var john = {
  name: 'John',
  greet: function(person) {
    alert("Hi " + person + ", my name is " + this.name);
  }
};var fx = john.greet;
fx("Mark");
// => "Hi Mark, my name is " (or "Hi Mark, my name »
is Ray" depending on where you're trying it) 

Perhaps you’re not familiar with languages that treat functions as first-order values, in which case the line var fx = john.greet; may seem weird. This does not call the greet method, but creates a reference to it—an alias of sorts, if you will.  Hence, calling fx ends up calling the greet method. However, we’re apparently in some trouble all of a sudden: we’re explicitly using the this keyword, yet it does not use John. What gives?

This is the single most important issue with JavaScript binding—something I’ll refer to as “binding loss.”  It happens whenever you’re accessing a method through a reference instead of directly through its owner object. The method loses its implicit binding, and this stops referencing its owner object and goes back to its default value, which in this case is window (so if window had a name property by then, it would be used).

Recognizing binding-sensitive code patterns

Binding-sensitive code patterns involve passing method references, which usually happens through two possible means: either you’re assigning a method as a value, or you’re passing a method as an argument (which is essentially the same thing, when you think about it).

Consider the following simple class definition (Line wraps marked » —Ed.):

function Person(first, last, age) {
  this.first = first;
  this.last = last;
  this.age = age;
}
Person.prototype = {
  getFullName: function() {
    alert(this.first + ' ' + this.last);
  },
  greet: function(other) {
    alert("Hi " + other.first + ", I'm " + »
    this.first + ".");
  }
};

Let’s try it out (Line wraps marked » —Ed.):

var elodie = new Person('Elodie', 'Jaubert', 27);
var christophe = new Person('Christophe', »
'Porteneuve', 30);
christophe.greet(elodie);
// => "Hi Elodie, I'm Christophe." 

Looking good so far.  Let’s push ahead:

function times(n, fx, arg) {
  for (var index = 0; index < n; ++index) {
    fx(arg);
  }
}times(3, christophe.greet, elodie);
// => Three times "Hi Elodie, I'm undefined." 
times(1, elodie.getFullName);
// => "undefined undefined"

Whoa—we’re in trouble!  What’s with the undefined? We lost our binding when we passed greet and getFullName as arguments, so their this reference points to the window object, which does not have the first and last properties.  Boom.

When you do all your JavaScript heavy lifting by hand, as we just did, you’re usually more aware of such issues. But when you rely on a framework to handle the basics, binding can elude you, leaving you writing simple code that just borks. Consider the following Prototype-based snippet:

this.items.each(function(item) {
  // Process item
  this.markItemAsProcessed(item);
});

This code will trigger an error stating that the markItemAsProcessed method is undefined.  Why is that?  Because you just passed each a reference to an anonymous function, so this in there refers to window, not to what it was outside each. This is a very common mistake, and makes up a fair share of the questions on the framework mailing lists.

Binding explicitly

So how do we fix it?  We bind explicitly—that is, we explicitly state to what this will point to within the method when it gets called.  And how do we do that?  JavaScript provides us with two options: apply and call.

Apply within

Every JavaScript function is equipped with an apply method that allows you to call that function with specific binding (a specific this, if you will).  It takes two arguments: the binding object, and an array of the arguments to be passed to the function. Here’s an example based on our previous code:

var fx = christophe.greet;
fx.apply(christophe, [elodie]);
// => "Hi Elodie, I'm Christophe." 

The nice thing with an array is, you don’t need to know in advance which arguments the function you’ll call apply on will take. You can write code independent of the actual argument list—just construct the array any way you want, and pass it on.  You can also take an existing array of arguments and tweak it to your heart’s content before passing it along.

Call now

When you do know exactly which arguments you want to pass, call may feel nicer, as it takes the arguments themselves, not an array of them:

var fx = christophe.greet;
fx.call(christophe, elodie);
// => "Hi Elodie, I'm Christophe." 

However, with call you lose the flexibility of an array. It all depends on your particular situation: aside from this difference, apply and call have identical semantics and behavior.

Note, by the way, that the method does not actually need to belong to the object you’re binding it to: as long as it uses this in ways that are compatible with its binding (read: with members that exist in its bound object), we’re in the clear. Such flexibility is possible because JavaScript is a dynamic language that resolves member access at runtime—when the access happens—a feature sometimes referred to as “late binding.” You’ll also find late binding in just about every scripting language (e.g., Perl, Ruby, Python, PHP) and, incidentally, OLE Automation.

Losing the shackles

It’s nice to have a way to specify binding, but the problem is, you can only specify it at invocation time.  You can’t, say, specify it in advance and then let some other code invoke your properly bound method when it sees fit.  This is a major problem, because when we pass method references around, we’re doing just that: letting other code choose when to invoke methods.

So what we want is a way to persistently bind a method, so that we get a bound method reference, so to speak. The only way to achieve this requires us to wrap our original method in another one, that will perform the apply call.  Here’s a stab at it:

function createBoundedWrapper(object, method) {
  return function() {
    return method.apply(object, arguments);
  };
}

If you’re not too keen on JavaScript, the code above may confuse you a bit. The idea here is that calling createBoundedWrapper with a given object and method (which, presumably, belongs to said object) will produce a brand new function (the anonymous one we’re returning).


That function, when called, will take our original method and invoke apply on it, passing:

  1. the original object’s binding (the variable named object), and
  2. whatever arguments were provided at call time, as an array.

(Every function has an automatic arguments variable that behaves as an array of all the arguments that were passed to it.)

Let’s try it out (Line wraps marked » —Ed.):

var chrisGreet = createBoundedWrapper(christophe, »
christophe.greet);
chrisGreet(elodie);
// "Hi Elodie, I'm Christophe." 

Ah-ha!  It works!  We created a bound method reference based on christophe and its greet method.

JavaScript frameworks do it

Our createBoundedWrapper function is neat, but may prove a bit unwieldy. If you’re smart about your JavaScript work, you’ll probably rely on a framework to smooth out browser incompatibilities, ease DOM access, and enhance JavaScript. So let’s have a look at how a few popular JavaScript frameworks deal with method binding.

Prototype

Prototype has long equipped functions with a bind method that lets you do just that:

var chrisGreet = christophe.greet.bind(christophe);
chrisGreet(elodie);

Far too few people know that bind also allows you to do “partial application”—that is, pre-filling one or more arguments. For instance, let’s say you have a method that toggles the active status of a feature:

var coolBehavior = {
  // ...
  toggle: function(enabled) {
    this.enabled = enabled;
    // ...
  },
  // ...
};

You can easily define two shortcuts—enable and disable—in the following way (Line wraps marked » —Ed.):

coolBehavior.enable = coolBehavior.toggle.bind »
(coolBehavior, true);
coolBehavior.disable = coolBehavior.toggle.bind »
(coolBehavior, false);// And then:
coolBehavior.enable();

A note on proper usage: sometimes, bind was used for pre-filling only, without interest in the binding.  Something like the following may be seen in code:

function times (count, fx) {
  for (var index = 0; index < count; ++index) {
    fx();
  }
}
// ...
var threeTimes = times.bind(null, 3);
// ...
threeTimes(someFunction);

So as a side note, with Prototype 1.6, if you’re only interested in pre-filling, prefer curry—it preserves the current binding and focuses on argument pre-filling:

var threeTimes = times.curry(3);

Ext JS

The Ext JS library tailors binding through a method added to functions, called createDelegate. The syntax goes like this (Line wraps marked » —Ed.):

method.createDelegate(scope[, argArray] »
[, appendArgs = false])

First, note that the extra arguments you may specify are provided as an array, instead of inline: myMethod.createDelegate(scope, [arg1, arg2]), not myMethod.createDelegate(scope, arg1, arg2).

Another important nuance is that these arguments will replace whatever arguments you pass at call time, instead of resulting in partial application. If you want the latter, you need to pass true (which will append the argument array, when Prototype would prepend them instead) or an insert position as a third argument (typically, using zero will prepend).  Here’s an example lifted from the API documentation (Line wraps marked » —Ed.):

var fn = scope.func1.createDelegate(scope, »
[arg1, arg2], true);
fn(a, b, c); // => scope.func1(a, b, c, arg1, arg2);var fn = scope.func1.createDelegate(scope, »
[arg1, arg2]);
fn(a, b, c); // => scope.func1(arg1, arg2);var fn = scope.func1.createDelegate(scope, »
[arg1, arg2], 1);
fn(a, b, c); // => scope.func1(a, arg1, arg2, b, c);

Dojo

The Dojo toolkit also caters to method binding with the humorously named hitch function.  The syntax is:

dojo.hitch(scope, methodOrMethodName[, arg…])

Interestingly, the method can be passed either directly, or using its name. Extra arguments, if any, are passed before actual, call-time arguments. Here are a few examples:

var fn = dojo.hitch(scope, func1)
fn(a, b, c); // => scope.func1(a, b, c);var fn = dojo.hitch(scope, func1, arg1, arg2)
fn(a, b, c); // => scope.func1(arg1, arg2, a, b, c);

Base2

Dean Edwards’ superb Base2 library acts as a least common denominator of sorts to all JavaScript libraries by ironing out all the annoying differences in JavaScript implementations. It acknowledges a binding facility is needed and provides a simple bind function:

base2.bind(method, scope[, arg]);

Note the scope object comes second, not first. Aside from that, the semantics are strictly equivalent to Prototype’s bind or Dojo’s hitch:

var fn = base2.bind(func1, scope)
fn(a, b, c); // => scope.func1(a, b, c);var fn = base2.bind(func1, scope, arg1, arg2)
fn(a, b, c); // => scope.func1(arg1, arg2, a, b, c);

jQuery

jQuery does not provide such a binding facility. The library’s philosophy favors closures over binding and forces users to jump through hoops (that is, manually combine lexical closures and apply or call, much as other libraries do internally) when they actually need to pass along a piece of code referring to “instance members.”

Should you even bind?

Now that we’ve been through the details of binding, it’s only fair to stress that sometimes, binding is overkill.  Specifically, there’s a code pattern in which binding can be replaced, with significant performance profit, by using the lexical closure. (If you’re not clear on a what a closure is, don’t panic.)

Here’s the pattern: some code within a method relies on an anonymous function passed by reference to work. That anonymous function needs to access the surrounding method’s this keyword. For instance, assuming for a minute we have the each iterator within arrays, consider the following code again:

  // ...
  processItems: function() {
    this.items.each(function(item) {
      // Process item…
      this.markItemAsProcessed(item);
    });
  },
  // ...

The issue here is that the anonymous function holding the actual processing code is passed as an argument to each, and therefore loses the current binding.  When it attempts to call this.markItemAsProcessed, it crashes because window has no such method.

Many developers are quick to fix that with binding. Using Prototype, for instance, they would add the following tweak:

  // ...
  processItems: function() {
    this.items.each(function(item) {
      // Process item
      this.markItemAsProcessed(item);
    }.bind(this));
  },
  // ...

Notice the trailing call to bind. However, such code is not as good an idea as it may seem. We saw that achieving such a “bound reference” requires us to wrap the original method within an anonymous function, which means calling the bound method reference results in two method calls: our anonymous wrapper, and the original method. And if there’s one thing true of just about any language, it’s that method calls are costly.

In this situation, we have access to the original, desired this keyword in the same code location where we define and call the faulty function (the anonymous method we’re passing as an argument to each). We can simply save the proper this reference in a local variable, and use that inside our iteration function:

  // ...
  processItems: function() {
    var that = this;
    this.items.each(function(item) {
      // Process item
      that.markItemAsProcessed(item);
    });
  },
  // ...

Look, Ma!  No binding!  This code uses a language feature called “lexical closure.” In short, closures let code at point A access identifiers declared in scopes surrounding A. Here, our anonymous function has access to variables in the surrounding function—our processItems method. Such a closure will be maintained by the JavaScript runtime no matter what, so there is no extra cost to using it. Even if there were, I’m fairly confident that it would be far less than the cost of an extra function call at every turn of the loop.

Be cautious about your bindings: sometimes closures provide a simpler, shorter, and better way. (Which is, I believe, precisely why jQuery decided to “force” its users to think about the best option for each situation by having them deal with binding manually.) While closures do have their own set of problems—ill-employed, they can result in memory leaks for certain browsers—the usage I recommend here is pretty safe.

Takeaway points

To recap:

  • Any member access must be qualified with the object it pertains to, even when it is this.
  • Any sort of function reference (assigning as a value, passing as an argument) loses the function’s original binding.
  • JavaScript provides two equivalent ways of explicitly specifying a function’s binding when calling it: apply and call.
  • Creating a “bound method reference” requires an anonymous wrapper function, and a calling cost. In specific situations, leveraging closures may be a better alternative.

And now, with the help of this article, you’ll have no trouble in binding situations!

About the Author

54 Reader Comments

Load Comments