Blog

Subclassing (Inheritance)
Posted on September 19, 2020 in JavaScript by Matt Jennings

Factory Function Example

// userCreator is a factory function
function userCreator(name, score) {
  // Create an object newUser that includes
  // the properties from the userFunctions
  const newUser = Object.create(userFunctions);
  newUser.name = name;
  newUser.score = score;
  return newUser;
}

const userFunctions = {
  sayName: function() {
    console.log("I'm " + this.name);
  },
  increment: function() {
    this.score++;
  }
};

const user1 = userCreator("Suzy", 5);

console.log(user1.sayName());

// Inheritance below
function padUserCreator(paidName, paidScore, accountBalance) {
  const newPaidUser = userCreator(paidName, paidScore);
  Object.setPrototypeOf(newPaidUser, paidUserFunctions);
  newPaidUser.accountBalance = accountBalance;
  return newPaidUser;
}

const paidUserFunctions = {
  incrementBalance: function() {
    this.accountBalance++
  }
};

Object.setPrototypeOf(paidUserFunctions, userFunctions);

const paidUser1 = paidUserCreator("Alyssa", 8, 25);

paidUser1.increaseBalance();

console.log(paidUser1.sayName()); // "I'm Alyssa"

Object .call() Example

const obj = {
  num: 3,
  increment: function() {
    this.num++;
  }
};

const otherObj = {
  num: 10
};

obj.increment(); // obj.num 4

object.increment.call(otherObj); // otherObj.num now 11

/*
This always refers to thte object to the left of the dot 
on which function (method) is being called, 
UNLESS we override that by running the function using .call() or .apply()
which lets us set the value of this increment of the increment function
*/

Subclassing using .call() or .apply()

function userCreator(name, score) {
  this.name = name;
  this.score = score;
}

userCreator.prototype.sayName = function() {
  console.log("I'm " + this.name);
};
userCreator.prototype.increment = function() {
  this.score++;
};

const user1 = new userCreator("Phil", 5);
const user2 = new userCreator("Tim", 4);

user1.sayName(); // "I'm Phil"

function paidUserCreator(paidName, paidScore, accountBalance) {
  // In the userCreator.call() method below the keyword "this"
  // will refer to the "paidUserCreator" object 
  // and the "paidName" and "paidScore" parameters
  // reference the parameters passed into the "paidUserCreator" function
  userCreator.call(this, paidName, paidScore);
  // userCreator.apply(this, [paidName, paidScore]);
  this.accountBalance = accountBalance;
}

paidUserCreator.prototype = Object.create(userCreator.prototype);

const paidUser1 = new paidUserCreator("Alyssa", 8, 25);

paidUser1.sayName(); // "I'm Alyssa"

Using the class Keyword for Inheritance

// A class is a function/object combo that is a base class
class userCreator {
  // In the constructor method
  // the properties or methods
  // are directorly added to the user1 and user2 instantiated objects,
  // NOT in the __proto__ object
  constructor(name, score) {
    this.name = name;
    this.score = score;
  }
  // The methods below are added to the user1 and user2
  // objects' __proto__ properties which link to the 
  // userCreator prototype property
  sayName() {
    console.log("I'm " + this.name);
  }
  increment() {
    this.score++;
  }
}

const user1 = new userCreator("Phil", 4);
const user2 = new userCreator("Tim", 4);

user1.sayName();

/*
Below:
0.
Is a sub-class

1.
The increaseBalance method is added
to to paidUserCreator prototype object

2.
The extends keyword adds the userCreator.property
as a property of the __proto__ method in the
paidUserCreator which itself is a method of the prototype object.

3. The constructor method again is called whenever
the object is instantiated with the new keyword and the super() function call
passes in the paidName and paidScore parameters to the userCreator constructor
function in place of the name and score parameters.
*/
class paidUserCreator extends userCreator {
  constructor(paidName, paidScore, accountBalance) {
    super(paidName, paidScore);
    this.accountBalance = accountBalance;
  }
  increaseBalance() {
    this.accountBalance++;
  }
}

const paidUser1 = new paidUserCreator("Alyssa", 8, 25);

paidUser1.increaseBalance(); // this.accountBalance = 25

paidUser1.sayName(); // "I'm Alyssa"

Leave a Reply