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 byCat
andBear
:
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");
}
};
- The
eat
method is repeated in two places. The code can be edited to follow the DRY principle by creating asupertype
(or parent) calledAnimal
:
function Animal() { }
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log("nom nom nom");
}
};
- Since
Animal
includes theeat
method, you can remove it fromCat
andBear
:
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");
}
};
- We just edited the code in the spirit of DRY by moving the
eat
method to theAnimal
supertype
.
Inherit Behaviors from a Supertype
- In the previous post, we created a
supertype
calledAnimal
that defined behaviors shared by all animals:
function Animal() { }
Animal.prototype.eat = function() {
console.log("nom nom nom");
};
- This and the next part will cover how to reuse
Animal's
methods insideDog
without defining them again. It uses a technique called inheritance. This challenge covers the first step: make an instance of thesupertype
(or parent).
let animal = Object.create(Animal.prototype);
- You could also use this,
let animal = new Animal();
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 setsobj
as the new object'sprototype
. Recall that theprototype
is like the "recipe" for creating an object. By setting theprototype
ofanimal
to beAnimal's
prototype
, you are effectively giving theanimal
instance the same "recipe" as any other instance ofAnimal
.
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
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 ofAnimal
.This post covers the next step: set the
prototype
of thesubtype
(or child)—in this case,Dog
—to be an instance ofAnimal
.
Dog.prototype = Object.create(Animal.prototype);
- Remember that the
prototype
is like the "recipe" for creating an object. In a way, the recipe forDog
now includes all the key "ingredients" fromAnimal
.
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
-
beagle
inherits all ofAnimal's
properties, including theeat
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
- But
beagle
and all instances ofDog
should show that they were constructed byDog
and notAnimal
. To do so, you can manually setDog'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]
Add Methods After Inheritance
- A constructor function that inherits its
prototype
object from asupertype
constructor function can still have its own methods in addition to inherited methods. - For example,
Dog
is a constructor that inherits itsprototype
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;
- In addition to what is inherited from
Animal
, you want to add behavior that is unique toDog
objects. Here,Dog
will get abark()
function. Functions are added toDog's
prototype
the same way as any constructor function:
Dog.prototype.bark = function() {
console.log("Woof!")
};
- Now instances of
Dog
will have botheat()
andbark()
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()
-
beagle.eat()
would display the stringnom nom nom
in the console, andbeagle.bark()
would display the stringWoof!
.
Top comments (4)
Next up:
Using composition so you don't use inheritance
:DOf course haha as I’m going I’m learning
^ this!
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