Skip to content Skip to sidebar Skip to footer

Javascript Setting Object Properties With Value Type In The Prototype?

I always have set properties with a value type in the prototype of the object as this stops them having to be initialized every time the object is created. Since then I have done s

Solution 1:

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:

varClass = 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 = newClass();
  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 = [
  newClass(), newClass(), newClass()
];

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.*

functionClass() {}
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.*

functionBase() {}
Base.prototype.a = 1;
Base.prototype.b = 2;
Base.prototype.c = 3;

functionClass() {}
Class.prototype = newBase();

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:

functionBase() {
  this.a = 1;
  this.b = 2;
  this.c = 3;
}

functionClass() {
}
Class.prototype = newBase();

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.

Solution 2:

There is no benefit to store a property value in the prototype if that property's value will always (or most of the time) be changed at object's instanciation. You would only have an advantage when a value is shared across multiple instances, wich in that case will result in less memory usage, but won't necessary give better performances. Walking the prototype chain should be more expensive that performing a property lookup directly on the object.

Post a Comment for "Javascript Setting Object Properties With Value Type In The Prototype?"