Closure Based Instance Binding

In JavaScript, we frequently write functions where we wish to access |this| from another (typically outer) function. The |this| keyword does not inherit from outer functions like other variables, each function has its own |this| binding. For example, suppose we have a widget that needs trigger some code in response to a button being pressed. We might try:

buildRendering: function(){
  this.domNode.appendChild(document.createElement("button")).onclick = function(){
    if(this.ready){
      this.showMessage();
    }
  };
},
showMessage: function(message){
...

However, this code won’t work as intended, because |this| in the inner function refers to something different (the target DOM node in this case) than it did in the outer method. Often times developers use a bind() or hitch() function to force a function to have |this| be the same as an outer function, fixing this code as such (note this is only available in ES5, most JS libraries provide a function to do something similar):

buildRendering: function(){
  this.domNode.appendChild(document.createElement("button")).onclick = (function(){
    if(this.ready){
      this.showMessage();
    }
  }).bind(this);
},

Another technique used by developers, is closure based instance binding, where we assign |this| to a variable that can then be accessed by the inner function:

buildRendering: function(){
  var widget = this;
  this.domNode.appendChild(document.createElement("button")).onclick = function(){
    if(widget.ready){
      widget.showMessage();
    }
  };
},

Both techniques have their place, but I almost always use the latter. I wanted to give a few reasons:

  • Philosophical – JavaScript is foremost a closure-based language, with method dispatching as additional sugared mechanism built on the foundation property access and call operators. This is in contrast to other languages that place object oriented method dispatching as foundational with closures as something built on top of it. Every function in JavaScript has a closure on some scope (even if it is the global scope), and using closures to maintain references to different instances through different function levels is the essence of idiomatic JavaScript.
  • Clarity and readability – “this” is a very generic term, and in layered functions, its ambiguity can be make it difficult to determine what instance is really being referred to. Setting |this| to a variable lends itself to giving the instance a clearly articulated variable name that describes exactly what instance is being referred to, and can easily be understood by later developers without having to trace through bindings to see where |this| comes from. In the example above, in the inner function, it is clear that the are referring to the widget instance, as opposed to the node or any other instance that might get assigned to |this|.
  • Flexibility – Using closure based instance binding, we can easily reference a parent function’s instance without losing the ability to reference the inner function’s |this|. In the example above, we can access the widget instance, but we can also still use |this| to reference the target node of the event.
  • Code Size – After minification setting up access to the parent |this| instance requires (approximately, it can vary on minification techniques, this assumes variables are reduced to 2 bytes):
    function.bind() – setup: 9, each reference: 4
    closure-based – setup: 8, each reference: 2
    Some functions like forEach, already have an argument to define |this| for the callback function, in which case they have a shorter binding setup.
  • Reduced Dependencies – Function binding entails using ES5’s bind(), which reduces compatibility to only ES5 environments, or requires reliance on third-party library, decreasing your code’s portability and flexibility in being used in different contexts. Closure-based bindings rely on nothing but JavaScript mechanisms that have been supported by all VMs forever.
  • Performance – There are two phases of the performance to test, that varies on our mechanism of binding. First is the setup of the function. This can be dominant if the function is not called very often. Second is the actual function invocation. Obviously this is more important if the function is called frequently. From these tests you can see the clear, and often immense, performance advantage of closure based binding:
    Setup: http://jsperf.com/bind-vs-closure-setup
    Invocation: http://jsperf.com/bind-vs-closure-invocation
  • Of course there are there are certainly situations where it is appropriate to bind. If you are going to provide a method directly as an event listener, binding is often appropriate. However, it is worth noting that I have seen plenty of instances of creating a method specifically for an event listener, and when an anonymous inline function (with closure-based instance binding) could easily have been used.

    Advertisement