Inheritance
Hey ,
I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.
Please upgrade (use this link) access this content.
I'm super eager to help you learn more!
Hey ,
I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.
Please upgrade (use this link) access this content.
I'm super eager to help you learn more!
Inheritance is a loaded word in Object Oriented Programming. Programmers use it to mean different things.
To understand Inheritance, we need to define this word into its fundamental form.
Inheritance (in real life) is about getting stuff (like money and genes) from your parents.
Inheritance (in JavaScript) is about getting properties (and methods) from parent objects.
There are two ways to inherit properties:
Copy-pasting means you copy properties into the instance. When you copy-paste, each instance will have its own version of the property.
Other names for copy-pasting includes:
I prefer to call it copy-pasting because it’s easier to understand and remember.
Example: Let’s say you want to create a Human
constructor.
Human
has a firstName
and lastName
.Human
should also be able to say their names with a method called sayName
.function Human (firstName, lastName) {
// Properties
this.firstName = firstName
this.lastName = lastName
// Methods
this.sayName = _ => {
console.log(`${this.firstName} ${this.lastName}`)
}
}
You can create an instance with the new
keyword. Each instance will have its own properties. Properties are completely different from other instances.
const zell = new Human('Zell', 'Liew')
const vincy = new Human('Vincy', 'Zhang')
console.log(zell)
console.log(vincy)
Properties do not reference each other. If you change zell
's sayName
method, it does not affect vincy
's sayName
method.
zell.sayName = function () {
console.log('Hello World')
}
zell.sayName() // Hello World
vincy.sayName() // Vincy Zhang
When you delegate a task to another person (in real life), you ask that person to do the job for you.
When you delegate (in JavaScript), you ask the delegated object to call the property (or method).
Other names for Delegation via Prototype include:
I prefer to call it Delegation via Prototypes because this phrase describes what happens exactly. But I do use Prototypal Delegation and Delegation via Prototypes interchangeably.
Example: Let’s say you want to create the same Human
constructor that has firstName
, lastName
, and sayName
.
Each instance needs its own firstName
and lastName
properties. We’ll use the Copy-pasting method to create these two properties.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
sayName
can be shared among all instances.
We create it outside of the Human
constructor, inside a prototype
object. (All constructors have a prototype
object).
Human.prototype.sayName = function () {
console.log(`${firstName} ${lastName}`)
}
You can then create instances with the new
keyword as before:
const zell = new Human('Zell', 'Liew')
const vincy = new Human('Vincy', 'Zhang')
console.log(zell)
console.log(vincy)
Both instances don’t have a sayName
method.
But they can both say their own names.
zell.sayName()
vincy.sayName()
Instances can say their names because sayName
is declared inside the constructor’s prototype. If you expand the __proto__
object, you will see sayName
.
Note: In Firefox, __proto__
is <prototype>
Here’s what JavaScript does when you access a property:
Step 1: JavaScript checks if the property is available inside the object. If yes, JavaScript uses the property straight away.
Step 2: If the property is NOT inside the object, JavaScript checks if there’s a Prototype available. If there is a Prototype, repeat Step 1 (and check if the property is inside the prototype).
Step 3: If there are no more Prototypes left, and JavaScript cannot find the property, it does the following:
undefined
(if you tried to access a property).Diagrammatically, here’s how the process looks like:
If a property is found inside a prototype, JavaScript asks the prototype for the property.
Each instance effectively hands over the job of accessing the property (or calling the method) to the prototype. In other words, they delegate the job away to the prototype.
Hence, the phrase Delegation via Prototype.
When should you copy-paste? When should you delegate?
In theory, Copy-pasting can take up more memory because each instance contains more properties. And Delegation via Prototypes can execute slower because JavaScript needs to look inside the Prototype Chain.
But these are negligible performance costs in today’s browsers and computers. We don’t have to worry about using either option.
People say that JavaScript is powerful because it lets you use Prototypal Delegation. This hints that Prototypal Delegation is preferred.
However, people also say you should favour composition over inheritance. Since composition uses Copy-pasting, it hints that Copy-pasting is preferred over Prototypal Delegation.
Don’t make a conclusive decision right now. Let’s explore further into this topic and you will find an answer.
Learn how to do both for now.
You can copy-paste by writing properties inside the constructor function.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
this.sayName = _ => {
console.log(`${this.firstName} ${this.lastName}`)
}
}
Creating an instance:
const zell = new Human('Zell', 'Liew')
console.log(zell)
You can copy-paste by writing properties inside the constructor function.
class Human {
constructor (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
this.sayName = _ => {
console.log(`${this.firstName} ${this.lastName}`)
}
}
}
Creating an instance:
const zell = new Human('Zell', 'Liew')
console.log(zell)
You can copy-paste by writing properties inside the function that initialises the instance. In this case, the function is init
.
const Human = {
init (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
this.sayName = _ => {
console.log(`${this.firstName} ${this.lastName}`)
}
return this
}
}
Creating the instance:
const zell = Object.create(Human).init('Zell', 'Liew')
You can copy-paste by writing properties inside the object you’ll return.
function Human (firstName, lastName) {
return {
firstName: firstName,
lastName: lastName,
sayName () {
console.log(`${this.firstName} ${this.lastName}`)
}
}
}
Creating an instance:
const zell = Human('Zell', 'Liew')
You delegate via prototypes by writing properties inside a prototype
object.
function Human (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Human.prototype.sayName = function () {
console.log(`${firstName} ${lastName}`)
}
Creating an instance
const zell = new Human('Zell', 'Liew')
console.log(zell)
Prototypal Delegation is easier in Classes compared to constructors. You can write the property directly inside the class.
class Human {
constructor (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
// This method uses prototype delegation
sayName () {
console.log(`${this.firstName} ${this.lastName}`)
}
}
Pay attention to the difference in syntax between classes and objects. This is one common mistake for developers who’re new to the class
syntax.
,
.,
Creating an instance:
const zell = new Human('Zell', 'Liew')
You can write properties directly inside the constructor object.
const Human = {
init (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
return this
},
sayName() {
console.log(`${this.firstName} ${this.lastName}`)
}
}
Creating the instance:
const zell = Object.create(Human).init('Zell', 'Liew')
Factory Functions are different from the other three flavours. They cannot use Prototypal Delegation by themselves.
You need to use one of the above three flavours to achieve Prototypal Delegation with Factory Functions.
This means wrapping one of the above flavours inside a function.
Example: Prototypal Delegation with a class:
function createHuman (...args) {
return new Human(...args)
}
Example: Prototypal Delegation with OLOO:
function createHuman (...args) {
return Object.create(Human).init(...args)
}
Although it is possible, we don’t normally use Prototypal Delegation with Factory Functions. We Copy-paste properties instead. I’ll share more about this topic in Composition vs Inheritance.