0

This tutorial on prototypical inheritance uses the following code as an example of a Constructable object:

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

var tom = new Person('tom');

But then goes on to say that if they want to change the Person object that tom was constructed with, then it should be done by altering Person.prototype:

Person.prototype.say = function (words) {
    alert(this.name + ' says "' + words + '"');
};

But why does the prototype (which is Person) have to be altered? Why not just change Person directly like so:

Person.say = function (words) {
    alert(this.name + ' says "' + words + '"');
};

Is there a difference?

Bryce
  • 6,440
  • 8
  • 40
  • 64
  • http://jsfiddle.net/AWHJu/ Yeah, the latter doesn't work. The function is not the same as the returned class. – scragar Jul 18 '14 at 10:10
  • Can you go into some more detail as to why? If you make it an answer, I can mark it as correct. – Bryce Jul 18 '14 at 10:13
  • The value of `this` will not point to a person instance when you do Person.say(words) you'd always have to do `Person.say.call(aPersonInstnace,words)` More on prototype and constructor functions here: http://stackoverflow.com/a/16063711/1641941 – HMR Jul 18 '14 at 10:22

3 Answers3

2

There is an important distinction to make between the function, and the object returned when treating the function as a constructor.

Person.say = function()

Isn't actually assigning a property to the function, which is it's own object, this has no effect on the generated objects, which inherit the prototype of the Person, overwritten with any changes made within the constructor call itself(hence why this.name still works).

var Person = function (name) {
    this.name = name;
};
var tom = new Person('tom');
console.log(tom.__proto__);
// Object {}
Person.prototype.say = function (words) {
    alert(this.name + ' says "' + words + '"');
};
console.log(tom.__proto__);
// Object {say: function}

When you call a method on tom if tom doesn't have the method it will look at the prototype, see if that has the method, you're not adding the method to tom ever, only the prototype it inherits from.

scragar
  • 6,764
  • 28
  • 36
1

The following code binds the say function to the object prototype. When you create a Person instance, the function is called against the data in this instance.

Person.prototype.say = function (words) {
    alert(this.name + ' says "' + words + '"');
};

The following code binds the say function to the object in a static fashion (thus, not available per-instance)

Person.say = function (words) {
    alert(this.name + ' says "' + words + '"');
};

The following alternative is this, which is a per-instance function, but is not bound to the prototype, rather the say function is created per instance, in the same way that name is created.

Just FYI, this method is NOT recommended (I'm just adding this for completeness) - It is recommended to bind your instance functions to the prototype:

var Person = function(name) {
    this.name = name;
    this.say = function(words) {
        alert(this.name + " says " + words);
    };
};

Prototype vs Per-instance:

Binding functions to the prototype (Person.prototype.say = function...) consumes less memory as one function is shared across all instances of the object.

Binding functions per-instance (this.say = function...) consumes more memory because a function is created for every instance created (nothing is shared), though this has the advantage of being able to access private members, which is not possible with prototype bound functions.

Overview:

Static binding: Person.say = function() { ... }

Prototype binding: Person.prototype.say - function() { ... }

Instance binding: function Person() { this.say = function() { ... } ... }

Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
0

The difference is in memory occupation.

In your case using or not prototype does not change because you have only one istance of Person.

But if you create a lot of istance every istance will have own say function, instead with prototype the function will be shared.

Pinku
  • 3
  • 1
  • 2
    That's totally wrong. Person.say and Person.prototype.say both would have one say method no matter how many instances you create. – HMR Jul 18 '14 at 10:25
  • Yes that's right, but if you don't use prototype each istance of Person will have own say method (many function, not one function). Try to create two person without protoype, on the second modify the say method, the result will be that each person will have different methods. With prototype this will not occur. – Pinku Jul 18 '14 at 10:36
  • The information isn't wrong but doesn't answer the question. Your answer describes the difference between `this.say` and `Person.prototype.say` but the question was about the difference between `Person.prototype.say` and `Person.say`. – HMR Jul 18 '14 at 12:27
  • No, no, no, wait.... this.say alone means nothing... The point is that Person.say is a function=object=heap occupation and if you create ten new Person() you will have ten new say function, one for each person. With Person.prototype.say you will have only one function=object=heap allocation for every new Person(). I think this is a big difference e very very important. – Pinku Jul 18 '14 at 12:51
  • Nope, Person is a function and a function is an object so you can add members on it. `Person.say=function` has no affect on the amount of `say` functions created when I create 10 persons (var ben=new Person,july=new Person()...). When I have `function Person(){this.say=function()...` then every instance I create will create a `say` function. But the OP didn't ask that, he asked about the difference between `Person.say=function()...` and `Person.prototype.say=function()...` Both declarations have nothing to do with the amount of instances you create. – HMR Jul 18 '14 at 15:12