Why defining properties in the prototype is considered an antipattern

In usual object-oriented languages, you have a definition of the class describing members, methods and the constructor.

In JS, the definition of the "class" (it is not really class like in other languages... sometimes the term pseudoclass is used) is the constructor itself. If your object is parametrised by name, it makes sense to write

function Person(name) {
    this.name = name;
}

i.e. the property name must be set in the constructor.

Of course, you can write

function Person(name) {
    this.name = name;
    this.describe = function() { ... };
}

and it will work as you expect.

However, in this case you are creating a separate instance of the method with every call of the constructor.

On the other hand, here:

Person.prototype.describe = function () {
    return "Person called "+this.name;
};

you only define the method once. All instances of Person will receive a pointer (called __proto__ and not accessible by programmer in most browsers) to Person.prototype. So if you call

var myPerson = new Person();
myPerson.describe();

it will work, because JS looks object members directly in the object, then in its prototype etc. all the way up to Object.prototype.

The point is that in the second case, only one instance of the function will exist. Which you will probably agree that is a better design. And even if you don't, it simply takes less memory.


There's nothing wrong with that code. This is supposedly what is meant:

function Person(name) {
    this.name = name;
}
Person.prototype.age = 15; //<= adding a hardcoded property to the prototype

Now you will see this:

var pete = new Person('Pete'), mary = new Person('Mary');
pete.age; //=> 15
mary.age  //=> 15

And most of the time, that's not what you want. Properties assigned to the prototype of a constructor are shared between all instances, properties assigned within the constructor (this.name) are specific for the instance.


As arxanas says, the article mentions data properties.

The reason, I assume, is that data is typically specific to an instance, so it does not make sense to add it to the prototype.

Furthermore, if your data is of a mutable type, e.g. an array, and you assign it to the prototype, then this array instance is shared between all instances and you cannot use it as if every instance had its own array.


Example: The following leads to incorrect behaviour:

function Set() {

}

// shared between instances
// each instance adds values to **the same** array
Set.prototype.elements = [];

Set.prototype.add = function(x) {
   this.elements.push(x);
};

It should be:

function Set() {
    // each instance gets its own array
    this.elements = [];
}

Set.prototype.add = function(x) {
   this.elements.push(x);
};

To sum it up:

  • Add properties that should be shared between all instances to the prototype.
  • Assign instance specific data inside the constructor function.