I was using inheritance and I noticed that there are three ways to get the same result. What's the difference?
function Animal(){
}
Animal.prototype.doThat = function() {
document.write("Doing that");
}
function Bird(){
}
// This makes doThat() visible
Bird.prototype = Object.create(Animal.prototype); // Solution 1
// You can also do:
// Bird.prototype = new Animal(); // Solution 2
// Or:
// Bird.prototype = Animal.prototype; // Solution 3
var myVar = new Bird();
myVar.doThat();
As you can see I proposed three solution. Each one of them make the method doThat() visible.
If I comment all of them there is an error indeed.
If I decomment only one of them the program works.
So... what's really the difference between the three solution?
Bird.prototype = Animal.prototype; // Solution 3
Since this assigned Animal.prototype
directly to Bird.prototype
, all changes you make to the latter will also be reflected in Animal
and all other classes that inherit from it.
For example:
Bird.prototype.fly = function() {
console.log('I can fly.');
}
var some_animal = new Animal();
some_animal.fly(); // this will work
This is certainly not what you want. Not only will every method of this subclass available for other subclasses, but if you override parent methods in subclasses, the subclass that was defined last will override the changes of the other subclasses.
In your question title you seem to refer to this as "prototype copy". This is not correct, since no copy is created. Animal.prototype
and Bird.prototype
will refer to one and the same object.
Bird.prototype = new Animal(); // Solution 2
This has been a common way to setup inheritance for a long time but it has two major drawbacks:
Animal
requires arguments, which do you pass? Passing random, meaningless arguments just to make the function call work seems to be bad design.Animal
might have side effects, like increasing an instance counter, but in this moment you actually didn't create a new instance (or don't want to), you just wanted to setup the inheritance.
Bird.prototype = Object.create(Animal.prototype); // Solution 1
That's the way you should do it now (until a better solution comes). All you really want to do is hook up Animal
's prototype into the prototype chain of Bird
. It avoids all the drawbacks of the previous solutions.
To make it work properly though, you also have to call the Animal
constructor inside the Bird
constructor. It's like a call to super
in other programming languages:
function Bird(){
Animal.call(this);
}
This ensure that any commands/changes made to a new Animal
instance are applied to the new Bird
instance.
It is also good practice to assign the correct value to the constructor
property of the prototype. It usually refers to the function the prototype "belongs to", but in all of the solutions above, Bird.prototype.constructor
will refer to Animal
. So we have to do:
Bird.prototype.constructor = Bird;
This property is not used internally, so you only have to do this if your own code relies on it. However, if you create a library to be used by others, they will probably expect the property to have to correct value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With