Explicit binding

In notebook:
FrontEndMasters Advanced JavaScript
Created at:
2016-10-03
Updated:
2016-10-03
Tags:
Fundamentals JavaScript

2. Explicit binding

  function foo() {
  console.log(this.bar)
}

var bar = "bar1";
var obj = { bar: "bar2" };

foo();        // "bar1"
foo.call(obj) // "bar2"
​.call​ or ​.apply​ take the ​this​ binding as the first parameter.Talks about that many people complain that the ​this​ binding gets lost when the code gets complex and often falls through to the global object.
But sometimes we want ​this​ to be very predictable. For example with Ajax calls (callbacks) the ​this​ falls back to the global object. Or click handlers on a button for example. 

The solution is hard-binding. It's possible to hard-bind the ​this​ to a function so it always points to the same object. 

How to create a hard binding:
  function foo() {
  console.log(this.bar);
}

var bar = "bar1";
var obj = { bar: "bar2" };

var orig = foo;
foo = function() { orig.call(obj); };

foo();        // "bar"
foo.call(obj) // ???
We have overwritten ​foo​ on line #9 so that it will always call the original ​foo​ function with the ​obj​ bound as ​this​, through the ​orig​ pointer.

So now, no matter how ​foo​ is called (click handler, ajax, etc.) it's always bound to the same object. 
Let's create a bind utility.
  function bind (fn,o) {
  return function () {
    fn.call(o);
  };
}

function foo() {
  console.log(this.bar);
}

var bar = "bar1";
var obj = { bar: "bar" };
var obj2 = { bar: "bar2" };

foo = bind(foo,obj);

foo();        // "bar"
foo.call(obj2) // still "bar"
With this "trick", the call site is now at line #2. Even when we call it as line #18. Now we can put the ​bind​ on the function ​prototype​.:
  if(!Function.prototype.bind2) {
  Function.prototype.bind2 =
    function (o) {
      var fn = this; // the function!
      return function () {
        return fn.apply(o,arguments);
      };
    };
}

function foo(baz) {
  console.log(this.bar + " " + baz);
}

var obj = { bar: "bar" };
foo = foo.bind2(obj);

foo("baz"); // "bar baz"
This is solution is more powerful (returns values, passes ​arguments​ etc.)

Line #16: implicit calling rule applies, so on line#4 ​this​ will be the ​foo​ function. 
As of ES5 ​bind​ is built-in the language. 
Shows the polyfill on MDN. It's similar to ​bind2​. The MDN polyfill is more adherent to the specs.