I've actually benchmarked this sort of thing, and if memory serves, the prototypal model is usually slower than assigning values directly to an object. The exception would be in cases where instances are largely identical and instantiating occurs far more frequently than property access.
So, if you define your objects like this:
var Class = function() {};
Class.prototype.p1 = 1;
Class.prototype.p2 = 1;
Class.prototype.p3 = 1;
You avoid a performance hit at instantiation time, copying the properties to each object. But, That performance shows its head when those properties are accessed or modified. And, if you happen to access those properties without modifying them, you incur the performance hit of walking the prototype chain every time you access them (because they're never copied to the local instance). But, if you have many properties and only access a small handful of them for each instance, this is probably ideal.
for (var i = 0; i < 100000; i++) {
var x = new Class();
console.log(x.p1);
// ignore p2-p99. we don't need them right now.
}
On the other end of the spectrum, if you need to iterate over the properties in a small handful of instances many times, you're better off avoiding the hit of walking the prototype chain.
var Class = function() {
this.p1 = 1;
this.p2 = 1;
this.p3 = 1;
}
Each instance gets its own copy of p1, p2, and p3 at creation time. And the prototype chain doesn't need to be consulted when we access any of them.
var instances = [
new Class(), new Class(), new Class()
];
for (var i = 0; i < 1000000; i++) {
console.log(instances[i % instances.length].p1);
console.log(instances[i % instances.length].p2);
console.log(instances[i % instances.length].p3);
}
If I have time later, I'll benchmark this later to verify. Until then, all I can give you is the theory!
ADDENDUM
There are two not-necessarily-performance related benefits to using the prototype.
One, for relatively static properties (like functions), it conserves memory. Most applications don't bump up against any limits. But, on the off-change this is an issue for you, use the prototype.
Two, the prototype allows you to assign functions and properties to all existing instances of a class. To accomplish the same feat with instance-level properties, you'd need to find and iterate.
BENCHMARKS
Per my latest benchmarks, which I've only run on the latest versions of FF and Chrome for OS X, I used the following syntax for single-layer (non-inherited) class definitions:
prototype.*
function Class() {}
Class.prototype.a = 1;
Class.prototype.b = 2;
Class.prototype.c = 3;
this.*
function Class() {
this.a = 1;
this.b = 2;
this.c = 3;
}
Between the above two syntaxes, the this.*
syntax operates about 10.5% faster all-around.
Adding a level of inheritance, I used the following:
prototype.*
function Base() {}
Base.prototype.a = 1;
Base.prototype.b = 2;
Base.prototype.c = 3;
function Class() {}
Class.prototype = new Base();
this.*
function Base() {
this.a = 1;
this.b = 2;
this.c = 3;
}
function Class() {
Base.apply(this);
}
And in this case, I found the prototype.*
syntax to be about 38.5% faster all-around. The this.*
syntax was still slightly faster totalled between browsers for member access; but, the advantage wasn't nearly as noticeable as the instantiation advantage.
I also benchmarked a hybrid approach to inheritance:
function Base() {
this.a = 1;
this.b = 2;
this.c = 3;
}
function Class() {
}
Class.prototype = new Base();
Overall, it ran about 0.5% faster than the prototype.*
syntax (probably insignificant). However, it was interestingly about 1% slower during instantiation, but about 2% faster during member access than the prototype.*
syntax. Again, not terribly significant, but I can't help wonder whether those gains would scale as inheritance depth increases.
Be aware, of course, that these benchmarks weren't done in a well-controlled setting. I tend to see the noticeably wide gaps in performance as being significant. But, the lower percentages could very well be due to fluctuating CPU load on my machine.
All that said, I would probably advise using the this.*
in cases wherein no inheritance is occurring or wherein member access is far more common than class instantiation. And of course, if you're not pressed to squeeze every ounce of performance out of your web app, use the syntax that feels more intuitive to you and your team. Most web-apps will take on much more significant performance hits than the difference in object-building styles.
For instance, changing a background color,
document.body.style.backgroundColor = 'blue';
... is roughly 70% slower than instantiating the worst-performing constructor I benchmarked.