Isn't it fun having to learn two (or more) different ways of coding everything, just to be able to support Internet Explorer?

I discovered this morning that IE8 doesn't implement that most wondrous of typing and sanity savers, "bind".

Quick recap: "bind" is a method on a "Function" object which returns a function bound to a context of your choosing.  

Most commonly, I use it when attaching object functions to events, such that they will execute in the context of this object.  This is probably best illustrated with a highly contrived example:

var x = {
  foo: "Hello World!",
  fum: function()
  {
      console.log(this.foo);
  },
  bar: function()
  {
      $("b.clickity1").click(this.fum.bind(this));

      $("b.clickity2").click(this.fum);
  }
}
x.bar();

window.foo = "Goodbye cruel world!"

$("b.clickity1").trigger("click");

: Hello World!

$("b.clickity2").trigger("click");

: Goodbye cruel world!


What's it do?  We have an object with a property "foo" and a method "fum" which puts foo's value to the console log.

Another method, "bar", sets up a click handler (using jQuery) for some item on the page.  But we don't assign this.fum directly to the handler, we assign the function returned as a result of binding it to this object.  That means that when the click event calls our handler, the handler's "this" object is...this object.

A second click handler for another DOM object is set up with just this.fum passed through as the handler.

When we trigger the two click handlers manually, you can see the difference: In the first case, the handler has been called in the context of the x object.  In the second, it has been called in the context of the window object.  Or to put that a different way, the first click handler will force bar to be called with a "this" of "x", the second with a "this" of "window".

So you can see, bind makes it very easy to stay inside our private object context, however the handler is called.  You might use this in an object which sets up, say, a button toolbar, where the toolbar calls in to a blog object to save, cancel, embolden words etc.

But the genius simplicity of this bind call is missing from IE8 and before.  

Luckily, "call" and "apply" are still available.  Similar principals are at work with "call" - every function has a "call" method, who's first argument is the context to use.  So in the above example, instead of:


      $("b.clickity").click(this.fum.bind(this));

You would do this:

      var me=this; 
      $("b.clickity").click(function(){me.fum.call(me);});


Which is clearly a little more laboured and less readable.  It has its own uses though, and in some cases is more appropriate than bind.

"Call" takes a variable number of arguments and passes them straight through to the function unchanged:

me.foo.call(me, 3, 5, 7)
...
foo : function(prime1, prime2, prime3)
{
   ...
}

"Apply" is very, very similar to Call, except that it takes only two arguments: the context and an array of arguments to pass to the function:

args = [3, 5, 7]
me.foo.apply(me, args)
...
foo : function(prime1, prime2, prime3)
{
  ...
}

There is some more fun you can have with bind: you can pass in a variable number of arguments, which will be given to your bound function whenever it is called, before any others.

So where a click handler will normally be passed an Event object:

foo : function(e)
{
 ...do stuff...
}

You can arrange for things which are only in context at bind time to be given to the handler:

 $("b.clickity").click(this.fum.bind(this, 7));

foo : function(mostMagicalNumber, e)
{
   this.magic = mostMagicalNumber;
}

Notice the mostMagicalNumber comes before the Event object (e) that was passed at "call time".

Let's draw these things together to give us a usable "bind" in IE8 (And, in fact, on some mobiles):

if( ! Function.prototype.bind )

    Function.prototype.bind = function(context)

    {   

        var args = Array.prototype.slice.call(arguments, 1); 

        var me = this; // the function being called

        return function()

        {   

            return me.apply(context, new Array(args, arguments));

        }   

    }   


Enjoy.


...Click for More
Article
bind, call and apply
Internet Explorer
javascript
Programming