Reputation: 999
Can someone explain to me use of Me.prototype.constructor = Me;
and why is needed, when this code is working and without it?
In code prototype object is created on Me object and it is instantiated and replaced old prototype object. Why do I need to point to Me constructor in a given up code?
function Me(){
this.name = 'Dejan';
}
function You(){
this.name = 'Ivan';
}
Me.prototype = new You();
somebody = new Me();
Me.prototype.constructor = Me; // Why?
Me.prototype.foo = function(){
alert('Proto Me!'); // It always fire up this alert, ether constructor is pointing to Me or not... !
}
You.prototype.foo = function(){
alert('Proto You!');
}
somebody.foo();
alert(somebody.name); // Alert 'Dejan'
Upvotes: 10
Views: 1170
Reputation: 112827
If you replace the line
Me.prototype.constructor = Me; // Why?
with
console.log(Me.prototype.constructor);
Me.prototype.constructor = Me; // Why?
you will find that before setting it, Me.prototype.constructor
is You
, since Me.prototype
is an instance of You
due to the line
Me.prototype = new You();
So, the line with the // Why?
comment is necessary to "fix" this mistaken impression that you've given JavaScript by doing inheritance this way.
Essentially the problem comes about because you are trying to use prototypal inheritance to implement classical inheritance. Prototypal inheritance works on object instances, and has no concept of "classes" or even, really, "types," but JavaScript makes things extra confusing with the whole new
, .constructor
, and instanceof
business.
A more prototypal way of doing this kind of thing is to eschew constructors in favor of power constructors, i.e. functions that return an object with the form you desire:
function begetPart(partNumber, description) {
return Object.create({}, {
number: { value: partNumber },
description: { value: description },
describe: {
value: function () {
alert(this.description);
}
}
});
}
function begetTire(partNumber, speed) {
return Object.create(
begetPart(partNumber, "A tire"),
{
speed: { value: speed },
describe: {
value: function () {
alert(this.description + "; speed = " + this.speed);
}
}
}
);
}
var genericPart = begetPart(1234, "A widget");
genericPart.describe(); // alerts "A widget"
var tire = begetTire(4567, "fast");
tire.describe(); // alerts "A tire; speed = fast"
Here we use Object.create
to say "create an object instance based on this other object instance". The other instance is a new, empty object for begetPart
and a new "part instance" with some properties pre-filled for begetTire
.
This better reflects how JavaScript and prototypal inheritance actually works, since in prototypal inheritance object instances inherit from other object instances, without this whole "types" or "classes" idea getting in the way.
Upvotes: 5
Reputation: 14602
It's not needed, and it's not even needed for instanceof
contrary to popular belief (instanceof internally checks the prototype chain and does not need a constructor property). Normally, constructor
is inherently a non-enumerable property on a constructor's prototype
. Thus giving any objects instantiated by that constructor, a non-enumerable constructor
property, pointing to that constructor.
It's good to put it there if you need to, ideally non-enumerable. Some code will assume the existence of .constructor
on objects.
In the code you posted, yes, when doing inheritance that way, it's necessary to reset constructor (if you want it there), because the object you instantiated to act as the child prototype has a constructor property pointing to the wrong constructor (its constructor).
In ES5, you would do:
Child.prototype = Object.create(Parent.prototype, {
constructor: { value: Child, enumerable: false }
});
edit: Also, might be worth mentioning, when doing inheritance using the non-standard __proto__
, it's not necessary to reset constructor because __proto__
merely specifies and object's prototype, which it to say, the object on which lookups will be performed when an own property doesn't exist. A new prototype
will always have a property called constructor
.
So in doing:
var child = function() {};
child.prototype.__proto__ = parent.prototype;
You do not have to set constructor because child.prototype's base constructor property is still there. If accessed, no prototype chain lookups need to be performed.
Upvotes: 11