2020-05-25

A visual way to understand inheritanc...

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__):

prototype-Page-2

the orange line refers to the prototype chain.

1
2
3
4
5
6
7
8
function A(argu){
this.con = argu;
}
A.prototype.proto = ()=>{console.log(this)}
let a1 = Object.create(A.prototype)
let a2 = new A('a2')
a2.con // 'a2'
a1.con // undefined

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.

prototype-Page-3

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
2
3
a1 instanceof Function //true
a1.proto() //a1.proto is not a function
a1.prototype.proto() //this works

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
2
3
4
5
6
function F() {}; //an empty (without any this.method/prop)
function B(){}
function A(argu){this.con=argu}
F.prototype = A.prototype; //assign the prototype object to the new F function
B.prototype = new F() //assign the prototype of new object B to the instance of F function
B.protoype.constructor = B;
prototype-Page-4

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
2
let b1 = new B('b')
b1.con //undefined
prototype-Page-4-1

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
2
3
4
5
function B(arg){
A.call(this.arg)
}
let b1 = new B('b1')
let b2 = new B('b2')

What happened if we just directly assign the a instance of A to the B.prototype?

prototype-
1
2
3
4
5
6
function A(argu){this.con=argu}
B.prototype = new A('instance')
let b1 = new B()
let b2 = new B()
b1.con //'instance'
b2.con //'instance'

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.