That's not how you use prototypes, so let's rebuild it in a more standardised fashion:
function Animal(){
this.species = 'Undefined';
this.sound = 'silence';
}
Animal.prototype = {
speak: function(){
return "I am a " + this.species + ", hear me " + this.sound + "!";
}
}
function Cat(){
Animal.apply(this);
this.species = 'cat';
this.sound = 'miauw';
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.pounce = function(){ return 'Pounce!'; }
So what have we done here? We start out by creating a function
, this is generally known as our constructor. It is mostly used to set the parameters stored. Then we create a prototype object
, which contains the methods (and potentially prototyped parameters) for your prototype
.
To create a Cat, we create another function and start by applying the first function
with the current this
object. This allows you to inherit everything the original constructor did when running. It essentially runs the setup for Animal, but on our new Cat. Then you do your custom things, like setting the species to 'cat'. After that, we will make a copy of the pre-existing prototype of Animal
, and then append more methods to it.
Important to note is that all this goes into the prototype
key, and not __proto__
. Keys and variables starting with double underscores are things you should never touch and almost never use yourself - they are considered something the system does for you. The __proto__
you were seeing before is the result of the prototype
being applied programatically, and you can see it in the console, but it is not something you should mess with.
Now we can do something like this:
// Ignore this bit, it's a repeat of the code above
// so I condensed it to a single line. Otherwise, exactly the same.
function Animal(){ this.species = 'Undefined'; this.sound = 'silence';}Animal.prototype = {speak: function(){return "I am a " + this.species + ", hear me " + this.sound + "!";}}; function Cat(){Animal.apply(this);this.species = 'cat';this.sound = 'miauw';}Cat.prototype = Object.create(Animal.prototype);Cat.prototype.pounce = function(){ return 'Pounce!'; }
// Helper function so the code reads clearly,
// but also writes to the snippet and adds the linebreaks
// and strong tags where necessary
function w(m,s){document.write((s?'<strong>':'')+(m?m:'')+(s?'</strong>':'')+'<br />');};
// Create our variables with the animal and the cat
var justAnAnimal = new Animal();
var pussInBoots = new Cat();
w( 'Speaking', true ); w();
w( 'justAnAnimal.speak()', true );
w( justAnAnimal.speak() );
w( 'pussInBoots.speak()', true );
w( pussInBoots.speak() );
w(); w('Pouncing', true); w();
w( 'justAnAnimal.pounce()', true );
// Use variable.method to check if the method exist
// if it does, then execute it and write that with variable.method()
// Otherwise print a different message so we know whats going on.
w(
(justAnAnimal.pounce && justAnAnimal.pounce())
|| 'Not every animal pounces (method does not exist for this instance)!'
);
w( 'pussInBoots.pounce()', true );
w(
(pussInBoots.pounce && pussInBoots.pounce())
|| 'Not every animal pounces (method does not exist for this instance)!'
);
w(); w('Checking the type of your animals using instanceof', true); w();
w( 'is justAnAnimal an Animal?', true );
w( justAnAnimal instanceof Animal ? 'Yes' : 'No' );
w( 'is justAnAnimal a Cat?', true );
w( justAnAnimal instanceof Cat ? 'Yes' : 'No' );
w( 'is pussInBoots an Animal?', true );
w( pussInBoots instanceof Animal ? 'Yes' : 'No' );
w( 'is pussInBoots a Cat?', true );
w( pussInBoots instanceof Cat ? 'Yes' : 'No' );
body {
font-family: 'Monaco', 'Courier MS', courier, monospace;
font-size: 10px;
}
strong {
color: #777;
margin-right: 20px;
display: inline-block;
font-weight: normal;
}
I find this makes your code look cleaner as everything is very simple. The constructors, the prototype, everything falls into a pattern that is easy to distinguish, as well as clear to read.
Heres a comprehensive write up over at MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Inheritance_and_the_prototype_chain