Kevnz
8/20/2014 - 6:11 PM

Lazy binding of "this" for inherited JavaScript instance methods

Lazy binding of "this" for inherited JavaScript instance methods

// The more efficient way (maybe?)

function createLazyBoundMethod(Ctor, method, fn) {
  // Create a get accessor that, only when accessed the first time, creates
  // a bound method on the instance. If the property is never accessed, the
  // per-instance closure is never created.
  Object.defineProperty(Ctor.prototype, method, {
    enumerable: true,
    configurable: true,
    get: function() {
      var m = "__" + method;
      if (!this[m]) { this[m] = fn.bind(this); }
      return this[m];
    },
  });
}

// No closures are created in the constructor.

function Thing(prop) {
  this.prop = prop;
}

// One closure is created per-prototype method, up-front

createLazyBoundMethod(Thing, "setProp", function(prop) {
  this.prop = prop;
});

createLazyBoundMethod(Thing, "getProp", function() {
  return this.prop;
});
// The normal way

// In the constructor, binding all methods to the instance creates one closure
// per method, for every instance, at the time the instance is created. If
// there are 2 methods and 100 instances, that's 200 closures created up-front.

function Thing(prop) {
  this.prop = prop;
  for (var method in this) {
    if (typeof Thing.prototype[method] === "function") {
      this[method] = Thing.prototype[method].bind(this);
    }
  }
}

Thing.prototype.setProp = function(prop) {
  this.prop = prop;
};

Thing.prototype.getProp = function() {
  return this.prop;
};
// Let's assume we've got a situation where there's going to be a lot of
// binding, eg. doSomethingWith(myThing.getProp.bind(myThing)); and we want
// to simplify app code by reducing the number of times .bind(myThing) gets
// called.

var myThing = new Thing("Test");
myThing.getProp()          // "Test"
myThing.getProp.call(null) // "Test"

myThing.setProp("Another Test");
myThing.getProp()          // "Another Test"
myThing.getProp.call(null) // "Another Test"