I've drawn the following picture demonstrating how the objects are inherited ( function constructors are marked as blue, objects created from those constructors are marked as green):
Here is the code creating such hierarchy:
function Figure() {}
function Rect() {}
Rect.prototype = new Figure();
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = new Figure();
function Circle() {}
Circle.prototype = new Ellipse();
Now I want to check if new Square()
is inherited from the Rect
, so here is how I expect JavaScript engine to check it:
var s = new Square();
s instanceof Rect // ?
s.__proto__ === Rect.prototype // false
new Rect() new Figure()
s.__proto__.__proto__ === Rect.prototype // true
new Figure() new Figure()
So s instanceof Rect
should return true
. This is expected and is actually what is returned if I run the code. But then I want to check if new Circle()
is inherited from the Rect
, so I follow the same logic:
var c = new Circle();
c instanceof Rect // ?
c.__proto__ === Rect.prototype // false
new Ellipse() new Figure()
c.__proto__.__proto__ === Rect.prototype // true
new Figure() new Figure()
So, using this checking logic c instanceof Rect
should return true
, but if I actually run the code, c instanceof Rect
returns false. Am I misunderstanding the mechanism of the instanceof
operator?
The Prototypal Inheritance is a feature in javascript used to add methods and properties in objects. It is a method by which an object can inherit the properties and methods of another object. Traditionally, in order to get and set the [[Prototype]] of an object, we use Object.
That prototype object has its own prototype, and so on until an object whose prototype is null is reached. By definition, null has no prototype, and acts as the final link in this chain of prototypes. This is known as prototypical inheritance and differs from class inheritance.
In JavaScript, all objects have a hidden [[Prototype]] property that's either another object or null . We can use obj. __proto__ to access it (a historical getter/setter, there are other ways, to be covered soon). The object referenced by [[Prototype]] is called a “prototype”.
The most important difference between class- and prototype-based inheritance is that a class defines a type which can be instantiated at runtime, whereas a prototype is itself an object instance.
Your logic is right, but the initial assumptions were a bit wrong. It is possible to emulate regular class based inheritance with prototypes.
To reproduce the structure you have drawn us, I created the following code:
function Figure() {}
function Rect() {}
function Square() {}
function Ellipse() {}
function Circle() {}
Ellipse.prototype = Rect.prototype = new Figure();
Square.prototype = new Rect();
Circle.prototype = new Ellipse();
console.log("is Figure: " + (new Circle() instanceof Figure));
console.log("is Ellipse: " + (new Circle() instanceof Ellipse));
console.log("is Rect: " + (new Circle() instanceof Rect));
As you can see, new Circle() instanceof Rect
returns true as you provisioned. The problem is that by setting Ellipse.prototype
and Rect.prototype
to the same object, they basically become the same type (with multiple constructors).
So how do you fix it? Create different Figure
instances for prototypes, like this:
function Figure() {}
function Rect() {}
function Square() {}
function Ellipse() {}
function Circle() {}
Ellipse.prototype = new Figure();
Rect.prototype = new Figure();
Square.prototype = new Rect();
Circle.prototype = new Ellipse();
console.log("is Figure: " + (new Circle() instanceof Figure));
console.log("is Ellipse: " + (new Circle() instanceof Ellipse));
console.log("is Rect: " + (new Circle() instanceof Rect));
And now the result is what everyone would expect.
EDIT
I've redrawn your picture and drawn another one which illustrates how the objects really are based on your textual example, which is the same as my second code.
The original one: I highlighted the references which are taken in the expression Rect.prototype === new Circle().__proto__.__proto__
:
The second one:
PS
Today in 2016, not Circle.prototype = new Ellipse()
is the way you should implement inheritance, but use the standard class inheritance instead:
class Figure {}
class Rect extends Figure {}
class Square extends Rect {}
class Ellipse extends Figure {}
class Circle extends Ellipse {}
console.log("new Circle is Figure: " + (new Circle() instanceof Figure));
console.log("new Circle is Rect: " + (new Circle() instanceof Rect));
Given the example code in your question, c.__proto__.__proto__ === Rect.prototype
returns false
. new Figure
is called twice, and creates two different Figure
instances.
Different object instances are not equal.
function Figure() {}
function Rect() {}
Rect.prototype = new Figure();
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = new Figure();
function Circle() {}
Circle.prototype = new Ellipse();
var c = new Circle();
console.log('c instanceof Rect:', c instanceof Rect);
console.log('c.__proto__ === Rect.prototype', c.__proto__ === Rect.prototype);
console.log('c.__proto__.__proto__ === Rect.prototype', c.__proto__.__proto__ === Rect.prototype);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With