Created
August 20, 2014 18:11
-
-
Save cowboy/182caa67ad981294f384 to your computer and use it in GitHub Desktop.
Lazy binding of "this" for inherited JavaScript instance methods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment