DEV Community

loading...

Using Inheritance So You Don't Repeat Yourself & Notes.

rthefounding profile image Randy Rivera ・3 min read
  • There's a principle in programming called Don't Repeat Yourself (DRY). The reason repeated code is a problem is because any change requires fixing code in multiple places. This usually means more work for programmers and more room for errors.

  • Notice in the example below that the eat method is shared by Cat and Bear:

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

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

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

Bear.prototype = {
  constructor: Bear,
  eat: function() {
    console.log("nom nom nom");
  }
};
Enter fullscreen mode Exit fullscreen mode
  • The eat method is repeated in two places. The code can be edited to follow the DRY principle by creating a supertype (or parent) called Animal:
function Animal() { }

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

};
Enter fullscreen mode Exit fullscreen mode
  • Since Animal includes the eat method, you can remove it from Cat and Bear:
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");
  }

};
Enter fullscreen mode Exit fullscreen mode
  • We just edited the code in the spirit of DRY by moving the eat method to the Animal supertype.

Inherit Behaviors from a Supertype

  • In the previous post, we created a supertype called Animal that defined behaviors shared by all animals:
function Animal() { }
Animal.prototype.eat = function() {
  console.log("nom nom nom");
};
Enter fullscreen mode Exit fullscreen mode
  • This and the next part will cover how to reuse Animal's methods inside Dog without defining them again. It uses a technique called inheritance. This challenge covers the first step: make an instance of the supertype (or parent).
let animal = Object.create(Animal.prototype);
Enter fullscreen mode Exit fullscreen mode
  • You could also use this,
let animal = new Animal();
Enter fullscreen mode Exit fullscreen mode
  • but there are some disadvantages when using this syntax for inheritance, which are too complex for the scope of this example.

  • Object.create(obj) creates a new object, and sets obj as the new object's prototype. Recall that the prototype is like the "recipe" for creating an object. By setting the prototype of animal to be Animal's prototype, you are effectively giving the animal instance the same "recipe" as any other instance of Animal.

function Animal() { }

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

let beagle = Object.create(Animal.prototype)

beagle.eat(); // will display nom nom nom 
console.log(beagle instanceof Animal); // will display true
Enter fullscreen mode Exit fullscreen mode

Setting the Child's Prototype to an Instance of the Parent

  • In the previous section you saw the first step for inheriting behavior from the supertype (or parent) Animal: making a new instance of Animal.

  • This post covers the next step: set the prototype of the subtype (or child)—in this case, Dog—to be an instance of Animal.

Dog.prototype = Object.create(Animal.prototype);
Enter fullscreen mode Exit fullscreen mode
  • Remember that the prototype is like the "recipe" for creating an object. In a way, the recipe for Dog now includes all the key "ingredients" from Animal.
function Animal() { }

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

function Dog() { }

Dog.prototype = Object.create(Animal.prototype); // <----

let beagle = new Dog();
beagle.eat(); // will display when console.log nom nom nom
Enter fullscreen mode Exit fullscreen mode
  • beagle inherits all of Animal's properties, including the eat method.

Resetting an Inherited Constructor Property

  • When an object inherits its prototype from another object, it also inherits the supertype's constructor property.

  • Here's an example:

function Dog() { }
Dog.prototype = Object.create(Animal.prototype);
let beagle = new Dog();
beagle.constructor
Enter fullscreen mode Exit fullscreen mode
  • But beagle and all instances of Dog should show that they were constructed by Dog and not Animal. To do so, you can manually set Dog's constructor property to the Dog object:
function Animal() { }
function Dog() { }

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

Dog.prototype.constructor = Dog;

let beagle = new Dog();

console.log(beagle.constructor); // will display [Function: Dog]
Enter fullscreen mode Exit fullscreen mode

Add Methods After Inheritance

  • A constructor function that inherits its prototype object from a supertype constructor function can still have its own methods in addition to inherited methods.
  • For example, Dog is a constructor that inherits its prototype from Animal:
function Animal() { }
Animal.prototype.eat = function() { console.log("nom nom nom"); };

function Dog() { }
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Enter fullscreen mode Exit fullscreen mode
  • In addition to what is inherited from Animal, you want to add behavior that is unique to Dog objects. Here, Dog will get a bark() function. Functions are added to Dog's prototype the same way as any constructor function:
Dog.prototype.bark = function() {
  console.log("Woof!")
};
Enter fullscreen mode Exit fullscreen mode
  • Now instances of Dog will have both eat() and bark() methods.
function Animal() { }
Animal.prototype.eat = function() { console.log("nom nom nom"); };

function Dog() { }

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {  // <----
  console.log("Woof!")
}

let beagle = new Dog();
beagle.eat();
beagle.bark()
Enter fullscreen mode Exit fullscreen mode
  • beagle.eat() would display the string nom nom nom in the console, and beagle.bark() would display the string Woof!.

Discussion (4)

Collapse
iamntz profile image
Ionut Staicu

Using Inheritance So You Don't Repeat Yourself

Next up: Using composition so you don't use inheritance :D

Collapse
rthefounding profile image
Randy Rivera Author

Of course haha as I’m going I’m learning

Collapse
blindfish3 profile image
Ben Calder

^ this!

Collapse
aleron75 profile image
Alessandro Ronchi

I warmly recommend to read this article where Matthias Verraes explains that DRY is not about code but knowledge:

verraes.net/2014/08/dry-is-about-k...

Cheers

Forem Open with the Forem app