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!

Inheritance

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.

What is Inheritance?

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:

  1. Copy-Pasting
  2. Delegation through Prototypes

Copy-Pasting

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:

  • Concatenative Inheritance
  • Cloning
  • Mixins

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.

  • Each Human has a firstName and lastName.
  • Each 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)
Each instance has their individuality.

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
Properties do not reference each other.

Delegation via Prototypes

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:

  1. Prototypal Inheritance
  2. Prototype Inheritance
  3. Prototypal Delegation
  4. Prototype Delegation

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.

Instances don't have sayName method.

But they can both say their own names.

zell.sayName()
vincy.sayName()
Instances can say their names.

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>

sayName found in the prototype.

The Prototype Chain

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:

  • Returns undefined (if you tried to access a property).
  • Throws an error (if you tried to call a method).

Diagrammatically, here’s how the process looks like:

The Prototype Chain

The meaning of delegation

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.

Copy-pasting vs Prototypal Delegation

When should you copy-paste? When should you delegate?

Performance considerations

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.

Structure and Style

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.

Which should you choose?

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.

Copy-pasting in 4 flavours

Constructor Syntax

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)
Copy-pasting with constructors.

Class Syntax

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)
Copy-paste using Classes

OLOO Syntax

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')
Copy-paste with OLOO.

Factory Function Syntax

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')
Copy-pasting with Factory Functions.

Prototypal Delegation in 4 flavours

Constructor Syntax

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 with Constructors.

Class Syntax

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.

  • Properties in classes are NOT separated with ,.
  • Properties in objects are separated with ,

Creating an instance:

const zell = new Human('Zell', 'Liew')
Prototypal delegation with Classes.

OLOO Syntax

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')
Prototypal Delegation in OLOO.

Factory Function Syntax

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.