tonix
tonix

Reputation: 6939

JavaScript prototypal inheritance does this code differs one from the other?

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)?

Upvotes: 3

Views: 59

Answers (1)

Alnitak
Alnitak

Reputation: 339947

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.

Upvotes: 2

Related Questions