A visual way to understand inheritance & prototype
Disclaimer
This article is originally based on my understanding of this concept. No guarantee on the accuracy.๐
In JavaScript, there is actually no concept of real Class (in es6, class is purely syntax sugar ๐ฌ)
The inheritance was made by inheriting along the prototype chain. And itโs a real OOP language since you can create a new object directly from an object bypassing the class.
The keyword new <Constructor>
and Object.create(<Prototype object>
) method can both manuiplate the prototype chain (__proto__
):
the orange line refers to the prototype chain.
1 | function A(argu){ |
the new keyword and the .create method both combine the returned object to the prototype of the constructor function. However, the new object a2 will inheritage the this.con property constructor (a function) while the a1 will not.
Both a1 and a2 have access to the .proto method by searching along the prototype chain.
A common mistakes when I first bump into the idea of inheritance I have made was accidentally create an object from a constructor function rather than the prototype of the constructor.
As the figure shown, the incorrectly created object a1now is an instance of function. And have no access to method of A.prototype.proto:
1 | a1 instanceof Function //true |
The prototype object can be only found on a function. An object other than function have no pointer referencing to prototype.
Before ES6, when there isnโt a Object.create() method, the it canbe done by (what happened in the dashed square)
1 | function F() {}; //an empty (without any this.method/prop) |
Then the instance of B has the A.prototype on their prototype chian.
The side effect is that the instance of B has no instance property .con.
1 | let b1 = new B('b') |
If they need that property/method, the this.xx can be passed to the B by calling A.call(this,arg). So the instance property would bind to the B.
1 | function B(arg){ |
What happened if we just directly assign the a instance of A to the B.prototype?
1 | function A(argu){this.con=argu} |
The main drawback is that:
1 | b1.con ===b2.con ===a.con //true |
Which normally is not useful if two distinct instance share the same instance property.