3

I have a question about JS prototyping:

If I have the following constructor:

function Person(name) {
     if (!(this instanceof Person))
         return new Person(name);
     this.name = name;
}
Person.prototype.sayHello = function() {
    console.log("Hello from " + this.name);
}

Here I have a method sayHello bound to the prototype of Person, which is more memory efficient that this:

function Person(name) {
     if (!(this instanceof Person))
         return new Person(name);
     this.name = name;
     this.sayHello = function() {
        console.log("Hello from " + this.name);
     }
}

Just a glimpse:

Prototypal person:

enter image description here

Not-prototypal person:

enter image description here

As you see, the reference to the sayHello Function will be "shared" across all the person created, instead of just creating a new Function for each instantiated person. this will then mutate to point to the correct person whenever it is used inside the sayHello() context when sayHello() is called on that specific person.

Now, another variant:

function Person(name) {
     if (!(this instanceof Person))
         return new Person(name);
     this.name = name;
     this.__proto__.sayHello = function() {
        console.log("Hello from " + this.name);
     }
}

And the output is the same as for Person.prototype.sayHello, meaning that sayHello is shared across different persons.

But is there a difference between this two approaches? I guess no, because:

Person.prototype === bob.__proto__ // true

So really, when one should use the former (Person.prototype.* outside the constructor function) instead of the latter (this.__proto__.* inside the constructor function)?

tonix
  • 6,671
  • 13
  • 75
  • 136
  • **probably not the answer, just reference purpose** -- Did you check these good questions already? 1: http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work?rq=1 -- 2: http://stackoverflow.com/questions/2064731/good-example-of-javascripts-prototype-based-inheritance?rq=1 – briosheje Apr 16 '15 at 11:00
  • 4
    Always! Why would you want to mutate the prototype *every time* the constructor is called? Even though the method(s) would still be shared, every call to the constructor creates a new version of the method and throws away the old one. Just create the method once and be done with it. – Felix Kling Apr 16 '15 at 11:00
  • @FelixKling That's a good reason, but beside this, there aren't any other differences, right? – tonix Apr 16 '15 at 11:02
  • Not from a structural perspective. But your are still cresting a copy of the same function, and external code could keep a reference to an old copy around. – Felix Kling Apr 16 '15 at 11:04
  • Sorry, I didn't understand you, what do you mean with "cresting a copy of the same function"? – tonix Apr 16 '15 at 11:09
  • 2
    Ah stupid auto-correct. It supposed to be "creating". – Felix Kling Apr 16 '15 at 13:31
  • Ah, it makes sense now! :) – tonix Apr 16 '15 at 13:39

1 Answers1

2

To expand on Felix's comments.

The version that reads:

this.__proto__.sayHello = function() {
    console.log("Hello from " + this.name);
}

shouldn't be used.

Each and every time that the enclosing constructor is invoked the code above will also be run, creating a new copy of that anonymous function, and overwriting the reference currently held in the prototype.

Any code that happens to hold a reference to the previous instance of that function will continue to point to that old version.

In memory efficiency terms it's very similar to writing this.sayHello = function(...) because none of the instances actually share the same copy of the function. In code efficiency terms it's arguably worse (albeit equivalent to using Person.prototype.sayHello = ...) because every invocation requires an ascent up the prototype chain.

Alnitak
  • 334,560
  • 70
  • 407
  • 495