Binding vs. Closure Context Lookup

Binding is an extremely useful tool in a Javascript programmer's tool belt. It is used frequently on all parts of the stack. Front-end frameworks, server-side techniques, and Database Management System ORM interfaces like Sequelize or Mongoose all benefit from the abstraction of complexity that bind gives us programmers. In this post I wanted to explain fundamentally what bind does under the hood, why it's useful and some reasons you might want to use another pattern called context lookup.

First let's define the two patterns at play. They are very similar and usually have the same end result, but not always! Both are used to retain access to the context reference that is held, when we want to declare a function that will not be invoked immediately but passed on to another part of our program. This function is defined in the scope we are working in, but when it is invoked it will not be executing in the same scope. If we want to have valid reference and operate on an object in the scope where we originally defined the function, we have a little work to do! Below is an example of three scenarios. One where we don't save a context reference, another where we use a closure to access the correct this, and finally an example of bind.

//A function which will be shared by a couple different modules
var getter = function() { return this.val };  
//A global variable
val = 'fizz';

var module = {  
  fooMod: {
    val: 'foo',
    get: getter
  },
  barMod: {
    val: 'bar',
    get: getter
  }
};

module.fooMod.get(); // ----> foo

//Simply assigning the function a new variable name and invoking it 
//elsewhere returns 'fizz', because the function is invoked in global scope
var getFoo = module.fooMod.get;  
getFoo(); // ----> fizz

//The closure pattern will return 'foo' wherever the resulting function is invoked, due to execution contexts
var closedFooGet = function() {  
  return module.fooMod.get();
};
closedFooGet(); // ----> foo

//Binding also returns 'foo' no matter where the resulting function is invoked
var boundFooGet = module.fooMod.get.bind(module.fooMod);  
boundFooGet(); // ----> foo

In the first case, the function doesn't have reference to the object we want to operate on! The variable this will refer to global scope. The second pattern using closure works, if you need a refresher on how a closure works, check out my previous post. This pattern is considered to be sloppy by many, especially if you decide to be lazy with your variable naming (Pro tip: don't use var that = this or you will end up very confused). Binding looks significantly cleaner and gives the same end result. Or so it seems...

Let's take a look at a simplified version of bind that reveals the behavior we will examine today.

Function.prototype.bind = function(context) {  
  var func = this;
  return function() {
    return func.apply(context, arguments);
  };
};

The thing I want to bring your attention to is the key feature of bind. Bind saves a variable reference to this, the function to the left of the call-time dot on which bind is being invoked, and then the returned bound function references the original function by way of a closure. The apply method invokes that saved reference with the context we've passed in originally to bind. So bind also uses the closure pattern, how the heck is it any different from just using the first pattern shown in the example?? Using the simple bind definition above, can you walk through the behavior of the next example utilizing the same modules as before?

var getter = function() { return this.val; };  
val = 'fizz';

var module = {  
  fooMod: {
    val: 'foo',
    get: getter
  },
  barMod: {
    val: 'bar',
    get: getter
  }
};

var closedFooGet = function() {  
  return module.fooMod.get();
};
closedFooGet(); // ----> foo

var boundFooGet = module.fooMod.get.bind(module.fooMod);  
boundFooGet(); // ----> foo

module.fooMod = module.barMod;

boundFooGet();  
closedFooGet();  

If you try to run this snippet you will find that while the closed function now returns 'bar', the bound function still returns 'foo'. The reason for this is that during execution a closure pattern will always look up the variables value at run time, which by the time the closed function is invoked for the second time has been updated to point to the same object as barMod. However, the bound function saved it's context reference when bind was invoked. Reassigning fooMod later on does not affect what object the bound function points to. That's all there is to it.

You usually want to retain access to the original object and not ever worry that it might be reassigned, and bind is great for this reason. Sometimes though you actually do want maintain a reassigned reference, one important use case is when developing tests and substituting a method in the innards of your codebase with a mock, stub, or a spy. In these cases if your code implements bind on the substituted method the testing assertions may not behave as you expect them to! It would be easier to use a context lookup and know for certain your method has been reassigned at invocation.

Extra Credit

Below is the polyfill for bind, taken straight from the Mozilla Developer Network post on binding in Javascript. When trying to learn a new concept soundly or close conceptual gaps, I've found that checking out an official polyfill definition is a great way to check out what's going on and orient the concept around a professional-grade code snippet.

if (!Function.prototype.bind) {  
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}

There is a lot to unpack here in these few lines, such as type checking to make sure the object being bound is indeed a function, making sure the prototype chain stays intact, and using aArgs to give bind it's useful argument currying behavior (not the topic of this post, but check out this article about function currying). Take a moment to digest this code and look up the reasons for lines that confuse you, it will be worthwhile, as bind is useful and frequently used!

Side note: In the polyfill definition, instanceof checks to see whether the object on the left has the constructor's prototype property anywhere in it's prototype chain. For a normally declared function, the instanceof check is always going to evaluate to false, so we won't consider the other case here. After perusing Stack Overflow and brainstorming I can't quite think of a scenario where that case would come into play, if you know please drop me a line! When I find out I'll give an update.