13

Possible Duplicate:
Use of 'prototype' vs. 'this' in Javascript?

I went to various websites but not able to understand the difference between the following ways of adding methods to custom objects:

Method 1:

function circle(radius){
     this.radius = radius;
     this.area = function(){ return 3.14*this.radius*this.radius;}
}

Method 2:

function circle(radius){
     this.radius = radius;
}
circle.prototype.area = function(){ return 3.14*this.radius*this.radius; }

Are there any performance or design issues that one of the methods has and the other does not?

Community
  • 1
  • 1
aditya_gaur
  • 3,169
  • 6
  • 29
  • 43
  • possible duplicate of [Use of 'prototype' vs. 'this' in Javascript?](http://stackoverflow.com/questions/310870/use-of-prototype-vs-this-in-javascript) and [Prototype vs. Not, what are benefits?](http://stackoverflow.com/questions/1319325/prototype-vs-not-what-are-benefits) and [Advantages of using prototype, vs defining methods straight in the constructor?](http://stackoverflow.com/questions/4508313/advantages-of-using-prototype-vs-defining-methods-straight-in-the-constructor) and probably others... – Felix Kling Jun 08 '11 at 08:44
  • thanks @Felix...sorry for re posting it... – aditya_gaur Jun 08 '11 at 08:54
  • Here is a [link](http://www.packtpub.com/article/using-prototype-property-in-javascript) which discusses in detail. – aditya_gaur Jun 08 '11 at 09:48

2 Answers2

12

Here is one way to see the difference:

var circle1 = circle(1);
var circle2 = circle(1);
alert(circle1.area == circle2.area);

For Method1 you will see false while Method2 yields in true. That's because in the first case you assign a new closure function to each object created, two objects end up with different area functions even though both do the same thing. In the second case the objects share the same prototype object with its area method, that method is of course identical in both cases.

Usually Method2 is preferable for several reasons:

  1. Object creation is faster because only custom properties need to be initialized.
  2. You don't waste memory on instantiating multiple copies of the same thing.
  3. You can easily find out which of the object properties have custom values by calling Object.hasOwnProperty.

There are some disadvantages as well to keep in mind.

  1. You always spend time on setting up the prototype even if you never create any objects.
  2. Property access is slightly slower because the JavaScript engine needs to check object properties first and then the properties of the prototype object (modern JavaScript engines optimize this pretty well however).
  3. There is a common fall trap of putting objects or arrays on the prototype, these will be shared between all object instances.

Here is an example of the common mistake:

function NumberCollection()
{
}
NumberCollection.prototype = {
    numbers: [],
    sum: function()
    {
        var result = 0;
        for (var i = 0; i < this.numbers.length; i++)
            result += this.numbers[i];
        return result;
    }
}

var c1 = new NumberCollection();
c1.numbers.push(5);
alert(c1.sum());   // Shows 5
var c2 = new NumberCollection();
c2.numbers.push(6);
alert(c2.sum());   // Oops, shows 11 because c1.numbers and c2.numbers is the same

The correct approach here would be:

function NumberCollection()
{
    this.numbers = [];
}
NumberCollection.prototype = {
    numbers: null,
    sum: function()
    {
        var result = 0;
        for (var i = 0; i < this.numbers.length; i++)
            result += this.numbers[i];
        return result;
    }
}
Wladimir Palant
  • 53,866
  • 11
  • 93
  • 123
  • 1
    thanks for the detailed explanation...you mean to say in general the functions that are to be shared among all the instances must be declared using the prototype property and the the properties must be declared within the object. – aditya_gaur Jun 08 '11 at 09:15
  • 1
    Not only functions. Initial values of properties should also be declared on the prototype - if all object instances should have a property `obj.type == 4` unless changed explicitly then it makes most sense to declare `type: 4` on the prototype rather than assigning this value in the constructor each time. However, as I said you should be careful assigning non-primitive types (objects or arrays) in the prototype because these can be changed and you probably don't want these changes to affect all object instances. – Wladimir Palant Jun 08 '11 at 09:45
5

The first method (let's call it type 1) adds the area() function to the object itself. Every time you construct a circle object with new, its body will be copied (!) to the new instance.

The second method (type 2) adds the area() function to the object prototype (the prototype is "one level up" in the hierarchy). Every time you create a new instance of circle only the radius property will be copied.

Now when you call area() on an instance of the second object, JavaScript cannot find that function on the object itself. Now it "goes up" the prototype chain and uses the first function of that name it finds.

Now this has several implications:

  1. New objects instances will be smaller (less physical code)
  2. You can change the implementation of area for all existing objects of type 2 at once and while they live (by changing the prototype), you can't do that for type 1
  3. You can override the functionality of area in a single instance of type 2 while keeping the "original implementation" of the function around
Tomalak
  • 306,836
  • 62
  • 485
  • 598