I have the following code:
class Polygon {
constructor() {
this.name = "Polygon";
}
}
class Rectangle {
constructor() {
this.name = "Rectangle";
}
}
class Square extends Polygon {
constructor() {
super();
}
}
Object.setPrototypeOf(Square, Rectangle);
const instance = new Square();
console.log(instance.name); // Rectangle
My understanding is:
Instance__proto__
: Points to Square.prototype to inherit instance methods.Subclass.__proto__
: Points to Rectangle to inherit static methods and properties.Square.prototype.__proto__
: Points to Polygon.prototype to inherit the parent class's instance methods.My Question:
In the code above, after using Object.setPrototypeOf(Square, Rectangle)
, the Square._proto_
is now pointing to Rectangle and not Polygon for all static properties. And for inheriting all the other methods Square.prototype._proto_
points to Polygon.prototype
. So, then I expect super()
in Square to invoke Polygon's constructor, since Square extends Polygon. However, it seems like super() is invoking Rectangle's constructor instead. I'm confused now, what all gets changed when Object.setPrototypeOf(Square, Rectangle)
is run, seems like there is a gap in my understanding.
What's missing is where the value of super
is coming from.
A base class (as in not extending another class) is prototyped on Function.prototype
. For example
Object.getPrototype(Polygon) === Function.prototype
A class extending another causes two things to happen:
The extended class object is prototyped on the class being extended and not on Function.prototype
. For example
Object.getPrototypeOf(Square) === Polygon
The extended class's prototype
property is prototyped on the prototype
property of the class extended. For example
Object.getPrototypOf(Square.prototype) === Polygon.prototype
Note the constructor
value inherited from an extended class's prototype
is not modified and remains set to the extended class object. I.E.
Square.prototype.constructor === Square
This has ramifications: the super class of an extended object can't be determined from the constructor
property inherited by instances of the the extended class.
super
keyword to locate the super class object's contructor method.This code shows the effects of changing the object on which a Class Object is prototyped on for experimental purposes to see what happens. It is not something to do in real world programming.
class Polygon {
static ClassName = "Polygon";
constructor() { this.name = "Polygon instance" }
inheritsFrom() {return "Polygon"}
}
class Rectangle {
static ClassName = "Rectangle";
constructor() { this.name = "Rectangle instance"; }
inheritsFrom() {return "Rectangle"}
}
class Square extends Polygon {
constructor() {
super();
}
}
console.log("class Polygon is prototyped on Function.prototype: ",
Object.getPrototypeOf(Polygon) === Function.prototype, " (1) true expected");
console.log(Square.ClassName, " (2) static value 'Polygon' expected");
const instance = new Square();
console.log( instance.name, " (3) 'Polygon instance' expected")
console.log( instance.constructor.name, " (4) 'Square' expected")
// overwrite the object (the super class) on which Square is prototyped:
Object.setPrototypeOf(Square, Rectangle);
console.log( Square.ClassName, " (5) static value 'Rectangle' expected");
const instance2 = new Square();
console.log(instance2.name, " (6) 'Rectangle instance' expected");
console.log( instance2.constructor.name, " (7) 'Square' expected")
// instances of Square still inherit from Polygon.prototype
console.log("instance instanceof Polygon is ", instance instanceof Polygon,
" (8) true expected");
console.log("instance instanceof Rectangle is ",
instance instanceof Rectangle, " (9) false expected)");
console.log("instance inherits from ", instance.inheritsFrom(), " (10) 'Polygon' expected");
console.log("instance2 is an instanceOf Polygon ", instance2 instanceof Polygon,
" (11) true expected");
console.log("instance2.instanceof Rectangle is ",
instance2 instanceof Rectangle, " (12) false expected");
console.log("instance2 inherits from ", instance2.inheritsFrom(),
" (13) 'Polygon' expected");
Update: usage of __proto__
as an inherited getter to return null or the object on which another has been prototyped on has been marked as "NORMATIVE OPTIONAL, LEGACY" in ECMAScript and hence considered deprecated: use of __proto__
has been removed from test code.
In all of the above,
Polygon
and Rectangle
class declarations in test code both declare a static ClassName
property and a class method named inheritsFrom
ClassName
property value is inherited by Square
from the object on which Square
was prototyped at the time Square.ClassName
is evaluated.name
is an instance property set by the constructor called as super()
.constructor.name
is inherited by a class instance from the first object in their inheritance chain. The inheritance chain of Square
instances starts with Square.prototype
before going back to Polygon.prototype
, none of which is modified by test code.inheritsFrom
is a class method defined in class declarations for Polygon
and Rectangle
in test code