Use Inheritance So You Dont Repeat Yourself. How inheritance is declared?

Hi! Could anyone please explain to me, how does the program knows that cat and bear are the subtypes of animal? And how multi-level subtypes are declared? For example, animal => canine => terrier => scottish terrier.


function Cat(name) {
  this.name = name; 
}

Cat.prototype = {
  constructor: Cat, 
};

function Bear(name) {
  this.name = name; 
}

Bear.prototype = {
  constructor: Bear, 
};

function Animal() { }

Animal.prototype = {
  constructor: Animal,
    eat: function() {
    console.log("nom nom nom");
  }
};

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/object-oriented-programming/use-inheritance-so-you-dont-repeat-yourself

2 Likes

That code doesn’t. It seems you understand inheritance from some other programming language. Just do what the lessons tell you, and the answer will be given over the next two challenge waypoints.

4 Likes

Ok, thanks. I’m just having troubles with this particular topic so I had to start all over again.

1 Like
That's okay, many people have difficulty understanding object-oriented programming. The basic idea is that we want to be able to abstractly model real-world objects and store data relevant about them for our model. In the curriculum, it's important that each Animal has a name. So, in order to not repeat ourselves (DRY), we try to write the relevant code in one place so if we have to edit it later, maintenance becomes easier. It also makes the code easier to read for future readers, be they collaborators or ourselves in the future.

In the example at right, we may want a way to represent People, and store their name and address. These people may be Clients and/or Employees. Employees need additional information that is specific to them BECAUSE they are employees. Rather than store their address a second time, we create an Employee class of object that is ALSO a person because it inherits from Person. However, as an Employee, it also needs to know its Employee number, which a generic Person does not.

The inheritance can continue for multiple levels, eventually resulting in a tree of inheritance called a "class hierarchy", depicted at left.

Hope that background helped. Did you get through that lesson and the following two? Feel free to ask me questions to clarify.

4 Likes

Yes, that helps a lot, thank you! I’m moving along and there is another thing I need to understand in order to move forward: What is the principal difference between the two lines of code below? The first one is a prototype, the second one is an object. Both are objects, both can be used to create new instances, both derived from the same supertype. Right now I’m failing to understand why we need this two separate ways to create objects.

Dog.prototype = Object.create(Animal.prototype);

and

let terrier = Object.create(Animal.prototype);

1 Like

Okay, we first need to discuss the concept of a class and instances of that class. Let’s say you and I both worked at that company from my earlier reply. We would both be instances of the Employee class. We would both have properties in common, but the values can be different. For example:

vipatron = new Employee();
vipatron.name = "Vip";
vipatron.address = "Philadelphia";
vipatron.EmployeeID= "11111";

SMGeorg = new Employee();
SMGeorg.name = "Egor";
SMGeorg.address = "St. Petersburg";
SMGeorg .EmployeeID= "22222";

Let’s start with the second line of code:
let terrier = Object.create(Animal.prototype);

In this case, terrier is an instance of Animal. It has whatever properties and methods an Animal had. It would be as if you wrote:
let terrier = new Animal();


On the other hand, there is some code that’s missing from your first line of code:

/* Missing Code Below*/
function Dog () {
  this.soundMade = "woof!"
 }
/* End of Missing Code*/
Dog.prototype = Object.create(Animal.prototype);

What’s going on is that we are first declaring the Dog function. If we were to write myDog = new Dog(), myDog would be an object of type Dog because we used the new operator. If we accessed myDog.soundMade, it would return "woof!".

By virtue of functions in Javascript being full Javascript Objects (they inherit from the Object class), they have properties. One of those properties is called prototype. By assigning Dog.prototype to an instance of the Animal class, whenever an instance of Dog is created (by Object.create(Dog.prototype) or new Dog()), Javascript looks at Dog.prototype and says: okay, there is a specific instance of Animal from which we are copying our new Dog object. The fact that a subclass’ prototype is an instance of the superclass’ prototype means that after making the subclass prototype assignment, we can then add more properties to the prototype of the subclass, for example:

Dog.prototype.constructor = Dog;
Dog.prototype.showHappiness = function (){ console.log("wagging tail...") };
myInheritedDog = new Dog();
myInheritedDog.eat(); //inherited from Animal
myInheritedDog.showHappiness();

The console should show two lines:

nom nom nom
wagging tail...
4 Likes

So the CLASS notion is something like a level of inheritance. Class is a parent constructor function from which we can derive new instances or new constructors which will inherit whatever the parent class already has.

From what you’re saying I gathered that prototype (although itself being an object) is a property of a constructor function which can be set for the whole group of lower level instances. By changing properties of prototype we change properties of all the instances derived from this prototype (following the principle of DRY). Is it necessary for a group of instances to have a common prototype? I thought they will inherit everything from the parent constructor object, so we could just change properties of constructor.

This concepts will surely take some time to sink in.

1 Like

There are two concepts you have to dissect off of one another:

  1. The abstract concept of classes of objects and how objects in one class may inherit the properties of a (more general/parent/base class, aka superclass):
    • in the picture above, “Predator Wild Cats” is a class. It is a subclass of the superclass “Mammal.” The single lion depicted, let’s call him Simba, is a single Instance of the “Predator Wild Cats” class. It is not an abstract concept, it is a real object that is being instantiated in the real world. It’s like you have a Platonic Ideal of what a chair is, and all real-world chairs fit into the “idea” or “class” of real-world objects that are chairs. Conversely, what you sit on is an instance of the concept/class of “chair.”
  2. The specific syntax by which Javascript classes (constructor functions) inherit the properties of a superclass:
function Superclass (initialParameter) {
  this.superclassProperty1 = initialParameter;
}
Superclass.prototype = {
  constructor: Superclass,
  this.classMethod () {
    //some commands
  }
}

function Subclass(initialParam) {
  this.subclassProperty = initialParam;
}
Subclass.prototype = new Superclass("a value") // a real instance of the abstract class of supertype.

Subclass.prototype is a real object. We can assign and delete properties to it. When it is created, it is created by calling the new operator Superclass() function. Subclass.prototype.prototype == Superclass.prototype.

[EDIT]: I made a mistake in the last line of code. It should have read new Superclass, not new Subclass. Hopefully my comment and discussion after the code made that clear. It was my bedtime when I wrote that reply.

3 Likes

Thank you once again for your time and effort! After reading and watching additional materials, I realized that this topic is much broader than I expected. But thanks to your explanation I finally have some understanding of what’s going on here. At least theoretically. My last question is how do we create a simple three stage collection of objects inheriting properties from one another? I still have troubles with practical implementation.

For example

Superclass
Creature
Properties
main task: survive and reproduce

Subclass1
Mammal
Properties
main task: survive and reproduce
+
blood: warm

Subclass2
Dog
Properties
main task: survive and reproduce
+
blood: warm
+
secondary task: help human

1 Like

Thank you for aggressively pursuing knowledge and forcing me to learn this better myself. I used MDN’s Object-Oriented Programming for Beginners, and learned that my earlier example was missing a call to superclass constructors to bind the this pronoun to the results of those constructor functions. Below you’ll find code that works, and a pen in which it is live now. I recommend you open the browser console to get a better experience that lets you traverse the object prototype chain:

function Creature () {
  this.mainTask = "survive and reproduce";
}

function Mammal () {
  Creature.call(this);
  this.blood = "warm";
}

Mammal.prototype = Object.create(Creature.prototype); //Make the template from which we make new instances (prototype) an instance of Creature. Our "this.x = y" statements in the Mammal constructor function (capitalized name by convention) are applied to any instances created by calling new Mammal(). Those instances will inherit (through Mammal.prototype) any methods or this-bound variables that were defined on that prototype (Creature, so they get Creature.mainTask).
Mammal.prototype.constructor = Mammal; // otherwise it would still be Creature

function Dog () {
  Mammal.call(this);
  this.secondaryTask = "help human";
}
Dog.prototype = Object.create(Mammal.prototype);
Dog.prototype.constructor = Dog;

let myDogRex = new Dog();
console.log(myDogRex);
console.log("myDogRex.mainTask: ", myDogRex.mainTask);
console.log("myDogRex.blood: ", myDogRex.blood);
console.log("myDogRex.secondaryTask:", myDogRex.secondaryTask);

3 Likes

Thank you very much for your example, it wasparticularly illuminating. I use Visual Studio with Quokka plugin for inline code evaluation.

2 Likes

Think you for the MDN link. It was very helpful.