views:

174

answers:

5

Hello,

I read here (Douglas Crockford) using prototype operator to add methods to Javascript classes saves also memory.

Then I read in this John Resig's article "Instantiating a function with a bunch of prototype properties is very, very, fast", but is he talking about using prototype in the standard way, or is he talking about his specific example in his article?

For example, is creating this object:

function Class1()
{
   this.showMsg = function(string) { alert(string); }
}
var c = new Class1();
c.showMsg();

slower than creating this object, then?

function Class1() {}
Class1.prototype.showMsg = function(string) { alert(string); }
var c = new Class1();
c.showMsg();

P.S.

I know prototype is used to create inheritance and singleton object etc. But this question does not have anyhting to do with these subjects.


EDIT: to whom it might be interested also in performance comparison between a JS object and a JS static objet can read this answer below. Static object are definitely faster, obviously they can be usued only when you don't need more than one instance of the object.

A: 

I'm sure that as far as instantiating the object goes, it's way faster and also consumes less memory, no doubts about that, but I would think that the javascript engine needs to loop through all the properties of the object to determine if the property/method invoked is part of that object and if not, then go check for the prototype. I am not 100% sure about this but I'm assuming that's how it works and if so, then in SOME cases where your object has a LOT of methods added to it, instantiated only once and used heavily, then it could possibly be a little slower, but that's just a supposition I haven't tested anything.

But in the end, I would still agree that as a general rules, using prototype will be faster.

SBUJOLD
There will be some overhead accessing properties in the prototype, but most engines use a hash table, so adding lots of properties doesn't matter. I think IE is the exception, and does need to loop through each property.
Matthew Crumley
Yeas as I was writing this I figured there has to be some optimizations that has been made over the years... so I guess in fact this adds to the fact that adding methods/properties to the object is taking up time cos the map/table would need to be rebuilt/updated ?
SBUJOLD
Yes, adding lots of properties would cause the table to be rebuilt eventually.
Matthew Crumley
+8  A: 

It was an interesting question, so I ran some very simple tests (I should have restarted my browsers to clear out the memory, but I didn't; take this for what it's worth). It looks like at least on Safari and Firefox, prototype runs significantly faster [edit: not 20x as stated earlier]. I'm sure a real-world test with fully-featured objects would be a better comparison. The code I ran was this (I ran the tests several times, separately):

var X,Y, x,y, i, intNow;

X = function() {};
X.prototype.message = function(s) { var mymessage = s + "";}
X.prototype.addition = function(i,j) { return (i *2 + j * 2) / 2; }

Y = function() {
    this.message = function(s) { var mymessage = s + "";}
    this.addition = function(i,j) { return (i *2 + j * 2) / 2; }
};


intNow = (new Date()).getTime();
for (i = 0; i < 1000000; i++) {
    y = new Y();
    y.message('hi');
    y.addition(i,2)
}
console.log((new Date()).getTime() - intNow); //FF=5206ms; Safari=1554

intNow = (new Date()).getTime();
for (i = 0; i < 1000000; i++) {
    x = new X();
    x.message('hi');
    x.addition(i,2)
}
console.log((new Date()).getTime() - intNow);//FF=3894ms;Safari=606

It's a real shame, because I really hate using prototype. I like my object code to be self-encapsulated, and not allowed to drift. I guess when speed matters, though, I don't have a choice. Darn.

[Edit] Many thanks to @Kevin who pointed out my previous code was wrong, giving a huge boost to the reported speed of the prototype method. After fixing, prototype is still around significantly faster, but the difference is not as enormous.

Andrew
+1 for doing science.
David Wolever
+1 well thanks so much for the effort you put in doing this.
Marco Demajo
No problem! It was a neat question.
Andrew
I can also verify that this benchmark looks correct… Although I'm curious about the low Safari number. What version are you using? On my machine, I see: FireFox 3.6.8: 5030/377, Safari 5.0: 3037/264.
David Wolever
It would also be interesting to see the time breakdown — ie, how much time it takes to instantiate each of `X` and `Y`, how much time it takes to look up a property (ex, `var tmp = x.message;`) and how much time it takes to call a property (ex, `x.message('hi')`).
David Wolever
@David Wolever - My Safari is 5.0.6553.16, which got pushed out fairly recently. I'm on a Mac though. I'm not sure why I don't use Safari more. It's ludicrously fast and the debugger is vastly superior over Firebug, but stupidly I never use it except when I have to. I tried what you suggested. A single property lookup adds about 10% above instantiation-only. Both methods showed roughly the same increase. So there doesn't seem to be any additional cost or savings to using either method. That kind of surprised me. Again, it would be far better to try this with a real-world example.
Andrew
You could also do: X.prototype = { message: function() { ... }, addition: function() { ... }}Might make it look more "self-encapsulated" to you.
Ronald
@Andrew: Interesting… I'm on a mac too. And running the tests a few times had the same result. Maybe because I'm running them through the JS console (ie, Develop —> show error console -> paste -> hit enter)?
David Wolever
In your first loop you are iterating 1 million times but in your second loop you are only iterating 100 thousand times, so your time comparisons are not apples to apples.
Kevin
Thank you, @Kevin. Pretty dumb mistake. I've updated the answer. `prototype` is still the hands-down winner, but the scale of the win is less impressive. What's strange is how much faster Safari's `prototype` is compared to Firefox.
Andrew
FYI: here are the same test on my machine (loop reduced to 100K), but anyway results as absolute values are not comparable, but in percentage terms yes: IE8: Y922ms X593ms; SAFARI4: Y183ms X49ms; FF3.6: Y394ms X16ms
Marco Demajo
A: 

Intuitively, it seems that it would be more memory-efficient and faster to create functions on the prototype: the function's only created once, not each time a new instance is created.

However, there will be a slight performance difference when it's time to access the function. When c.showMsg is referenced, the JavaScript runtime first checks for the property on c. If it's not found, c's prototype is then checked.

So, creating the property on the instance would result in slightly faster access time - but this might only be an issue for a very deep prototype hierarchy.

harto
+2  A: 

I would guess that it depends on the type of object you want to create. I ran a similar test as Andrew, but with a static object, and the static object won hands down. Here's the test:

var X,Y,Z x,y,z;

X = function() {};
X.prototype.message = function(s) { var mymessage = s + "";}
X.prototype.addition = function(i,j) { return (i *2 + j * 2) / 2; }

Y = function() {
    this.message = function(s) { var mymessage = s + "";}
    this.addition = function(i,j) { return (i *2 + j * 2) / 2; }
};

Z = {
 message: function(s) { var mymessage = s + "";}
 ,addition: function(i,j) { return (i *2 + j * 2) / 2; }
}

function TestPerformance()
{
  var closureStartDateTime = new Date();
  for (var i = 0; i < 100000; i++)
  {
 y = new Y();
    y.message('hi');
    y.addition(i,2);
  }
  var closureEndDateTime = new Date();

  var prototypeStartDateTime = new Date();
  for (var i = 0; i < 100000; i++)
  {
    x = new X();
    x.message('hi');
    x.addition(i,2);
  }
  var prototypeEndDateTime = new Date();

  var staticObjectStartDateTime = new Date();
  for (var i = 0; i < 100000; i++)
  {
 z = Z; // obviously you don't really need this
    z.message('hi');
    z.addition(i,2);
  }
  var staticObjectEndDateTime = new Date();
  var closureTime = closureEndDateTime.getTime() - closureStartDateTime.getTime();
  var prototypeTime = prototypeEndDateTime.getTime() - prototypeStartDateTime.getTime();
  var staticTime = staticObjectEndDateTime.getTime() - staticObjectStartDateTime.getTime();
  alert("Closure time: " + closureTime + ", prototype time: " + prototypeTime + ", static object time: " + staticTime);
}

TestPerformance();

This test is a modification of code I found at:

http://blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspx

Results:

IE6: closure time: 1062, prototype time: 766, static object time: 406

IE8: closure time: 781, prototype time: 406, static object time: 188

FF: closure time: 233, prototype time: 141, static object time: 94

Safari: closure time: 152, prototype time: 12, static object time: 6

Chrome: closure time: 13, prototype time: 8, static object time: 3

The lesson learned is that if you DON'T have a need to instantiate many different objects from the same class, then creating it as a static object wins hands down. So think carefully about what kind of class you really need.

shmuel613
Well at least a +1 is due here! Thanks for sharing your thought and the test!!! I commonly use static object in JS (and often also in other languages, rather than using a Singleton) when I don't need to instantiate more than one instance of an object. I expected static objet to be faster, but I'm glad you made it clear here with also a test. Thanks again!
Marco Demajo