Bind in JavaScript

31 Jul 2014 · By Sarah Ransohoff

The web team here at Venmo works almost entirely in JavaScript. One function we use often is bind. Let's take a look at what's going on here.

Here's a simple example of how you might use bind:

var obj = {
  foo: function() {
    console.log(this);
    this.name = 'baz';
    (function() {
      console.log('inside func');
      console.log(this.name);
    }.bind(this))();
  }
}
obj.foo();
// Object {foo: function}
// inside func
// baz

In the example above, bind allows the function inside of foo's outer function to have access to this.name. If we did not bind then this.name would return undefined. And it would do so because this now refers to the global object. No good if we want to be able to work with the same this in a nested function.

So what is going on behind the scenes with bind? What's this sneaky guy doing? Well, bind returns a function with new or added context, optionally adding any additional supplied parameters to the beginning of the arguments collection. Let's take a look at a rewrite below.

Function.prototype.bind = function(ctx) {
  var fn = this;
  var args = arguments.slice(1);

  return function() {
    return fn.apply(ctx, args.concat(arguments));
  };
};

So, let's go through it:

  1. Bind takes a context (ctx).
  2. The function on which bind will be called is this
  3. The arguments (args) passed into the function include everything but the first argument, ctx
  4. bind returns a new function that applies ctx and args to the original fn

This is essentially how bind returns a function that will execute in a given context.

To really hammer it home, let's take a look at an instance where we do not use bind:

$('.gist-author img').click(function() { // my avatar image on gist.github.com :-P
  console.log(this);
  (function() {
    console.log('inside');
    console.log(this);
  })();
});
// if you click that image, you'll get the following...
// <img src="https://avatars1.githubusercontent.com/u/4968408?s=140" width="26" height="26">
// inside
// Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

Yikes. If we want to perform a function on the original this -- in this case, img -- we can't. Inside the inner function, this refers to the window because this defaults to window when inside a jQuery function. This is the problem that bind tries to solve: to allow us to be specific with our context.

Awesome. I hope that's helpful. It certainly helps us at Venmo.

Until next time,

Sarah Ransohoff