Defining Methods via Prototype VS Using This in the Constructor - Really a Performance Difference

Defining methods via prototype vs using this in the constructor - really a performance difference?

See http://jsperf.com/prototype-vs-this

Declaring your methods via the prototype is faster, but whether or not this is relevant is debatable.

If you have a performance bottleneck in your app it is unlikely to be this, unless you happen to be instantiating 10000+ objects on every step of some arbitrary animation, for example.

If performance is a serious concern, and you'd like to micro-optimise, then I would suggest declaring via prototype. Otherwise, just use the pattern that makes most sense to you.

I'll add that, in JavaScript, there is a convention of prefixing properties that are intended to be seen as private with an underscore (e.g. _process()). Most developers will understand and avoid these properties, unless they're willing to forgo the social contract, but in that case you might as well not cater to them. What I mean to say is that: you probably don't really need true private variables...

Advantages of using prototype, vs defining methods straight in the constructor?

Methods that inherit via the prototype chain can be changed universally for all instances, for example:

function Class () {}
Class.prototype.calc = function (a, b) {
return a + b;
}

// Create 2 instances:
var ins1 = new Class(),
ins2 = new Class();

// Test the calc method:
console.log(ins1.calc(1,1), ins2.calc(1,1));
// -> 2, 2

// Change the prototype method
Class.prototype.calc = function () {
var args = Array.prototype.slice.apply(arguments),
res = 0, c;

while (c = args.shift())
res += c;

return res;
}

// Test the calc method:
console.log(ins1.calc(1,1,1), ins2.calc(1,1,1));
// -> 3, 3

Notice how changing the method applied to both instances? This is because ins1 and ins2 share the same calc() function. In order to do this with public methods created during construction, you'd have to assign the new method to each instance that has been created, which is an awkward task. This is because ins1 and ins2 would have their own, individually created calc() functions.

Another side effect of creating methods inside the constructor is poorer performance. Each method has to be created every time the constructor function runs. Methods on the prototype chain are created once and then "inherited" by each instance. On the flip side of the coin, public methods have access to "private" variables, which isn't possible with inherited methods.

As for your function Class() {} vs var Class = function () {} question, the former is "hoisted" to the top of the current scope before execution. For the latter, the variable declaration is hoisted, but not the assignment. For example:

// Error, fn is called before the function is assigned!
fn();
var fn = function () { alert("test!"); }

// Works as expected: the fn2 declaration is hoisted above the call
fn2();
function fn2() { alert("test!"); }

Performance wise which is better: An object protype or an constructors native function?

When creating many objects of type DateGreeting all of them will have a copy of those methods which you have defined on constructor.

While working with that objects you are usually changing their properties, but the methods remain the same.

So declaring methods on prototype would be a more resource-saving approach. Therefore, you can work with many objects which share the same methods without copying methods to each instance.

Declaring methods on custom prototype is definitely better for performance:

// this method will be shared by all DateGreeting instances
DateGreeting.prototype.greeting = function () {
if(this.hours <= 11) {
return "Morning";
} else if (this.hours >= 12 && this.hours <= 17) {
return "Afternoon";
} else {
return "Evening";
}
}

var greeting1 = new DateGreeting(".greet");
var greeting2 = new DateGreeting(".greet");
console.log(greeting1, greeting2);
// the output:

output

While adding methods to constructor creates copy of each method on each object instance:

function DateGreeting(selector) {
...
this.greeting = function () {
if(this.hours <= 11) {
return "Morning";
} else if (this.hours >= 12 && this.hours <= 17) {
return "Afternoon";
} else {
return "Evening";
}
}
}

var greeting1 = new DateGreeting(".greet");
var greeting2 = new DateGreeting(".greet");
console.log(greeting1, greeting2);
// the output:

output2

Trying to understand the difference between prototype and constructor in JavaScript

It is pretty hard to wrap your mind around this concept if you are used to the ease of extending objects in other OOP languages, but I'll do my best to explain the uses of those and what is what. I am going to assume you are familiar with other OOP languages. Correct me if I'm wrong.

All functions have the prototype Function(). They are inheriting all base functionality from Function like toString() and valueOf().

Then there is a constructor. That is what you use to initialize an object with.

p = new Foo();

So in this case we have two things.

  • A function Foo with Function as prototype(Foo)
  • A Function object with Foo() as constructor(p)

(following me yet?)

The Foo() constructor can override some base functionality of the Function constructor or leave it as it is and make good use of it.

If you are familiar with OOP principles, The prototype is the base class, the constructor your current class. In OOP the above would be class Foo extends Function

You can also start inheritance with this entire setup of prototype and constructor making more complex objects as you go whilst sharing functionality.

For example this:

// Make an object initialiser extending Function. In OOP `class Foo extends Function`

function Foo(bar) {
this.baz = bar;
}
Foo.prototype.append = function(what) {
this.baz += " " + what;
};
Foo.prototype.get() {
return this.baz
}

Now lets say we want different ways to get baz out of there. One for console logging and one for putting it on the title bar.
We could make a big thing about our class Foo, but we don't do that, because we need to do wholly different things with the new classes that are made for different implementations. The only thing they need to share are the baz item and the setters and getters.

So we need to extend it to use an OOP term. In OOO this would be the desired end result class Title extends Foo(){}. So lets take a look at how to get there.

function Title(what) {
this.message = what;
}

At this point the Title function looks like this:

  • prototype Function
  • constructor Title

So, to make it extends Foo we need to change the prototype.

Title.prototype = new Foo();
  • prototype Foo
  • constructor Foo

This is done by initializing a new Foo() object against the prototype.
Now its basically a Foo object called Title. That is not what we want because now we can't access the message part in Title.
We can make it properly extend Foo() by resetting the constructor to Title

Title.prototype.constructor = Title;
  • prototype Foo
  • Constructor Title

Now we are faced with one more problem. The constructor of Foo doesn't get initialized so we end up with an undefined this.baz

To resolve that we need to call the parent. In Java you would do that with super(vars), in PHP $parent->__construct($vars).

In Javascript we have to modify the Title class constructor to call the constructor of the parent object.

So the Title class constructor would become

function Title(what) {
Foo.call(this,what);
this.message = what;
}

By using the Function object property Foo inherited we can initialize the Foo object in the Title object.

And now you have a properly inherited object.

So instead of using a keyword like extend like other OOP languages it uses prototype and constructor.

Should we add methods only to the prototypes of our objects?

One reason why one might prefer putting methods on the instance itself would be to ensure the correct this context while adding a method concisely. Getting this to work properly is a very common problem in JavaScript.

For example:

class Foo {
i = 0;
clickHandler = () => console.log(this.i++);
}

const f = new Foo();
window.onclick = f.clickHandler;

Difference of methods defined on this in contrast to defined in class body

When you do this.bar = function() { }; in the constructor, you're creating a new function for every instance, and assigning it to the bar property. This lets the function close over something in the constructor if you want it to. (And if you used an arrow function, the function would close over this and super.)

When you declare a method in the class, you're creating a single function on the prototype object that class will assign to instances, and reusing that function. This lets the function use super if it needs to access superclass features.

Both have their place depending on what you're doing. You can see that difference here:

class Foo1 {
constructor() {
this.bar = function() {};
}
}

class Foo2 {
bar() {}
}

const f1a = new Foo1();
const f1b = new Foo1();
console.log(f1a.bar === f1b.bar); // false

const f2a = new Foo2();
const f2b = new Foo2();
console.log(f2a.bar === f2b.bar); // true

Javascript prototype operator performance: saves memory, but is it faster?

Edit in 2021:

This question was asked in 2010 when class was not available in JS. Nowadays, class has been so optimized that there is no excuse not to use it. If you need to use new, use class. But back in 2010 you had two options when binding methods to their object constructors -- one was to bind functions inside the function constructor using this and the other was to bind them outside the constructor using prototype. @MarcoDemaio's question has very concise examples. When class was added to JS, early implementations were close in performance, but usually slower. That's not remotely true anymore. Just use class. I can think of no reason to use prototype today.


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 < 10000000; 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 < 10000000; i++) {
x = new X();
x.message('hi');
x.addition(i,2)
}
console.log((new Date()).getTime() - intNow);//FF=3894ms;Safari=606


Related Topics



Leave a reply



Submit