I was just looking through a new blog post from Brendan Eich over on
AMinuteWithBrendan where he went into some detail on Closures versus
Prototypal Patterns.
After listening to his pod cast, (you can find the transcript here), I decided to put
the two patterns to test. So I fired up a new test on JSPerf.com
Setting up the Closure Pattern
function ClosurePattern() {
this.someMethod = function someMethod() {
console.log('foo');
}
}
Setting up the Prototypal Pattern
function PrototypalPattern() {}
PrototypalPattern.prototype = {
someMethod: function() {
console.log('foo');
}
}
Setting up the Prototypal Hoisting Pattern
function sm() {
console.log("foo")
}
function PrototypalWithHoisting() {}
PrototypalWithHoisting.prototype = {
someMethod: sm
}
Results
Closure Pattern
The closure pattern is quick in Chrome, but not nearly as fast in all the other browsers.
Prototypal Versus Hoisting
Prototypal and hoisting run neck and neck in all browsers, with Prototypal winning out in Chrome.
Closure Versus Prototypal
Here we are can start to se the overall winner in object creation.
Closure, Prototypal, Hoisting
I threw this one up here so you can see all 3 types next to each other.
Conclusion
After look at this set of test, I really think it all depends on your use case. While the Closure Pattern lends itself to
readability and the ability to have both public and private variables as well as public and private methods, object creation is
much slower. Also, as Brendan points out, you aren’t getting the same functionality as creating an object via the Prototypal Pattern.
The closure pattern, the one where you have the method as a function expression inside the constructor, can actually be more
expensive. If you think about it, each time you call that constructor (let’s say you call it a million times), you have to
evaluate the method function expression. You have to evaluate the assignment “this.someMethod = function() { /*etc*/ }”. In
JavaScript, every time you evaluate a function expression, you get a new object. You can tell it’s a new object because
of “===”; you can also mutate it: it’s mutable. So you can set a certain property on it that would not show up on any other
instances — “someMethod”. You’d say “new ClosurePattern()” and assign that to x, and also set y to “new ClosurePattern()”.
Now you’ve got two instances. x.someMethod !== y.someMethod, and “x.someMethod.foo = 42” would not cause 42 to appear on
y.someMethod: they’d be different objects. That hurts! If you do a million constructions, you’ve got not just a million
instances of the ClosurePattern object, you’ve got a million “someMethod”s inside it.
Unless I was creating an application that requires creating millions of JavaScript objects, I would still recommend the Closure
Pattern for code re-use.
Doesn’t the prototypal version encourage code reuse the most? Since you can have inheritance?
So you can still inherit using the prototypal pattern even with closures. It just takes a bit more work. However the trade off for readability may be worth it.
// just make this a bit easier rather than a helper function.
Function.prototype.inheritsFrom = function( parentClassOrObject ){
if ( parentClassOrObject.constructor == Function )
{
//Normal Inheritance
this.prototype = new parentClassOrObject;
this.prototype.constructor = this;
this.prototype.parent = parentClassOrObject.prototype;
}
else
{
//Pure Virtual Inheritance
this.prototype = parentClassOrObject;
this.prototype.constructor = this;
this.prototype.parent = parentClassOrObject;
}
return this;
}
function ClosurePattern() {
this.someMethod = function someMethod() {
console.log('foo');
}
}
function inheritClass() {
this.otherMethod = function otherMethod() {
console.log("bar");
}
}
inheritClass.inheritsFrom(ClosurePattern);
// new class
var temp = new inheritClass();
temp.someMethod(); // outputs "foo"
temp.otherMethod(); // outputs "bar"
Of course, syntax highlighting on this page may make it a bit worse!
It was a very interesting post thanks for writing it!