Related Questions, but no mention of my specific 'bug' -
prototypes vs extending objects
Advantages of using prototype, vs defining methods straight in the constructor?
I have a performance issue I don't understand. I was creating a class with the ability to be both callable and have methods (similar to jQuery).
I allowed an 'opt out' of the callable part, assuming that it would be slower to extend a function with methods than to use a prototype. This assumption is correct in the most basic case.
However, when I actually timed my code and looked at the memory usage, I was surprised to discover the prototype approach being slower AND taking up more memory.
After looking into it, it became clear that it was only less efficient when calling the 'init' method that binds a DOM element to 'this'. If you comment out the call to init (line 49 in the fiddle), the prototype method is much faster, as I would expect.
jsfiddle here - http://jsfiddle.net/pnsfogem/1/
Edit: jsPerf laying out all of Bergi's suggestions below - http://jsperf.com/different-types-of-constructors-vs-extend
After running these perfs, it does look like it's only in the version of Chrome I'm running..
and all of the code needed to replicate.
var methods = {
select: function(selector){
var $this = this;
var scopedMethods = {
newMethod1: function( newParam ){
$this.newMethod1( selector, newParam );
},
newMethod2: function( newParam ){
$this.newMethod2( selector, newParam );
}
};
return scopedMethods;
},
init: function(){
// console.log(this); // Looks correct for all 2000 elements
this.$el = $( "<div>" ).appendTo( $("body") );
},
newMethod1: function( selector, newParam ){
// do stuff
},
newMethod2: function( selector, newParam ){
// do stuff
}
};
function getConstructor( noQuery ){
var returnedInstance;
if ( noQuery ){
var constructor = function(){};
constructor.prototype = methods;
returnedInstance = new constructor();
// Usage:
// var s = getConstructor( 'justPrototype' );
// s.newMethod1( '#whatever', 'stuff' );
}
else {
returnedInstance = function(){
return returnedInstance.select.apply( returnedInstance, arguments );
};
$.extend( returnedInstance, methods );
// Can use either of these ways:
// var s = getConstructor();
// s.newMethod1( '#whatever', 'stuff' );
// s( '#whatever' ).newMethod1( 'stuff' );
}
returnedInstance.init();
return returnedInstance;
}
// When calling init
// This is both faster and more memory efficient. Why?
var arr1 = [];
console.time('normal');
for (var i=0; i<1000;i++){
arr1.push( getConstructor() );
}
console.timeEnd('normal');
// arr1[0].$el != arr1[1].$el
var arr2 = [];
console.time('prototype');
for (var i=0; i<1000;i++){
arr2.push( getConstructor( 'justPrototype' ) );
}
console.timeEnd('prototype');
// arr2[0].$el != arr2[1].$el
so, my question is
Why is this the case? Am I doing something wrong?
Once they're instantiated, I would expect them to handle adding new properties to be relatively the same performance wise, but it seems to slow down the prototype approach by 10x.
( Obviously, there's other benefits / trade-offs to allowing access to a prototype vs having a function with no prototype, but I think they're outside the scope of this question )