Reputation: 714
I'm learning prototype based OOP in javascript recently. After reading lots of websites explaining the prototype mechanism in javascript, I settle down with this approach from Mozilla
Here are some snippets from Mozilla:
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
rect instanceof Rectangle // true.
rect instanceof Shape // true.
rect.move(1, 1); // Outputs, "Shape moved."
I understand that Rectangle.prototype = Object.create(Shape.prototype);
will set the prototype chain properly so that instance of Rectangle
will inherit methods from Shape
.
But the Rectangle.prototype.constructor = Rectangle;
line is a little bit confusing.
From this website I know that when we create a new object like function MyClass(){}
, javascript will set its prototype to an empty object and the MyClass.prototype.constructor
will point back to MyClass
. So Rectangle.prototype.constructor = Rectangle;
will fix the broken link since Object.create(Shape.prototype).constructor
still points to Shape
.
But if I remove this line, I will still get the following code running without a problem. I'm just feeling curious if there's any use case for the constructor attribute? What will go wrong if I just leave it pointing to the super class?
Upvotes: 3
Views: 222
Reputation: 8053
In your code it doesn't make any difference, as you still create your object using Rectangle
constructor (explicitly using the name of it: var rect = new Rectangle();
).
The difference is only in the case, when you've lost reference to object's constructor, or you simply don't know what is it:
// Shape - superclass
function Shape() {
this.x = 1;
this.y = 1;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info(this.x + " " + this.y);
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
//Rectangle.prototype.constructor = Rectangle;
console.info("RECT");
var rect = new Rectangle;
console.info(rect);
console.info(rect instanceof Rectangle);
console.info(rect instanceof Shape);
//console.info(rect instanceof Square); TypeError - Square must be a function, but is still not initialized
rect.move(1, 1);
console.info("RECT2");
var rect2 = new rect.constructor();
console.info(rect2);
console.info(rect2 instanceof Rectangle);
console.info(rect2 instanceof Shape);
// console.info(rect2 instanceof Square); TypeError - Square must be a function, but is still not initialized
rect2.move(1, 1);
console.info("RECT3");
var Square = rect.constructor;
Square.prototype.move = function(x, y) { // just to make it different
this.x *= x;
this.y *= y;
console.info(this.x + " " + this.y);
}
var rect3 = new Square();
console.info(rect3);
console.info(rect3 instanceof Rectangle);
console.info(rect3 instanceof Shape);
console.info(rect3 instanceof Square);
rect3.move(4, 4);
I commented out the line with setting the constructor. Uncomment it to see the difference in output. I have also added another way to use the constructor property - another inheritance example (Square
based on Shape
but with different move
method).
So if you don't fix this link, in the case I showed, you will use Shape
constructor, and creation of objects of the same type will become simply impossible. rect
was of both types, but rect2
is not anymore.
So assuming, even if you don't need it, it is a very good practice to fix this link to the correct constructor, as someone working with your code in the future may need it.
EDIT:
constructor
property doesn't affect anything in the object
itself. It's set once object
is created to save the reference
to the function
which created the object
. If you will need it in the future than it makes sense to have a correct one. I don't see any other issues.
Upvotes: 2
Reputation: 3085
instanceOf will return true if the object is of the specified object type in its inheritance chain. It has nothing to do with constructor property.
We can use constructor property if we want to initialize property or execute default code at the time of creation of Object.
For example in your example, if we want to create Rectangle always in red color, we can use constructor of Rectangle as follows:
function Rectangle() {
Shape.call(this); // call super constructor.
this.color = "red";
}
Hope this clear your query.
Upvotes: -1
Reputation: 17094
Setting a property this way will make it enumerable(a for in statement would list the constructor property).
var rec = new Rectangle();
'constructor' in rec; //true
You should be using Object.defineProperty
or pass in a second argument to Object.create.
Rectangle.prototype = Object.create(Shape.prototype, {constructor: {enumerable: false }});
var rec = new Rectangle();
'constructor' in rec; //
Please refer to this thread for more on the constructor property:
https://stackoverflow.com/a/4013295
Upvotes: 3