JavaScript’s Function.prototype.bind


The bind function allows you to set the context with which a function will execute. It takes in a ‘context object and returns a new function which has its context set to the passed in object. The variadic method, which exists on all function objects, provides a workaround for the annoying and elusive ‘this’ context issue in JavaScript.

As web developers; we all nearly need to create references to object methods at some time or the other. The annoying thing is that the original context is uusally lost when we need it most! Let’s see how bind can help in these scenarios.

var obj = {
    val: 10,
    getVal: function () {
         return this.val;
    }
};

obj.getVal();
//10

var valGetter = obj.getVal;
valGetter();
//undefined

var boundValGetter = valGetter.bind(obj);
boundValGetter();
//10

Function Signature

Function.bind(thisObj, arg1, arg2,…)

thisObj refers to the new context for the function. However if the newly returned function is used as a constructor (i.e. called using the new operator), the this context will be a new empty object as expected.

arg1, arg2,… are extra parameters that are prepended to the list of arguments that the newly bound function is called with. Assuming you declare two arguments in the original bind call and then pass three new arguments to the returned bound function, then the two original bound arguments appear before the three newly passed in arguments.

var fn = function () {};
var bound = fn.bind(window, 1,2);

#equivalent forms
bound(3);
fn.call(window, 1,2,3)

If the bound function is invoked as a constructor, then the bound arguments are still passed on.

Uses

The most common application would be to avoid the use of the ‘that = this’ pattern in JavaScript. This is especially the case when you need to pass in context to event handlers, use anonymous functions or do something similar.

var ordExample = {
     log : function () {
           console.log('logger called');
     },
     asyncCall : function (callback) {
          //...
          callback();
     },
     useAsync : function () {
          var that = this;
          this.asyncCall(function () {
               that.log();
          });
     }
}

//Bind form
var bindExample = {
     log : function () {
          console.log('logger called');
     },
     asyncCall : function (callback) {
          //...
          callback();
     },
     useAsync : function () {
          this.asyncCall(function () {
               this.log();
          }.bind(this));
     }
}

ordExample.useAsync();
//logger called
bindExample.useAsync();
//logger called

As seen from the example above, we can use this in all sort of scenarios – from timers, Ajax callback handlers, event handlers, custom objects etc.

Issues

You cannot unbind after binding a function; anytime you call the Function.prototype.bind, you get a new function which has its ‘this’ context already prefixed to the pre-supplied value.

var fn = function () {};
console.log(fn.bind(this)===fn.bind(this));
//false

Ben Cowboy Alman has written a Function.protoype.unbind polyfill here.

The other issue is that there is some overhead with using bind; it adds some overhead and is not as optimal as using the ‘this = that‘ approach (variable vs function). Here is a jsperf run for four various bind styles.

So that’s it; now go bind some functions.

3 Comments

·

Leave a Reply

    • Thanks Charles,

      The apply method invokes the function immediately while setting the context.

      Bind returns a new function with the context set to what you want. It is now possible to re-use this function in several places as you wish (not possible with apply).

      Please let me know if this explains it.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s