Let’s take a look at the code above.
A constructor function MyAnimalConstructor() is defined, which sets the properties adjective, color and species and the method eat for every object instantiated with it. We instantiate a myAnimal object with this constructor function, with strange, yellow and fish parameters, and call the eat method, which logs “Eating strange yellow fish” to the console.
Later, we add a move method to the prototype property of the MyAnimalConstructor() constructor function.
Even though the move method was added to the constructor function after the instantiation of myAnimal, calling the move method on myAnimal does its job, and logs “Moving strange yellow fish” to the console.
So how does this prototype property exactly work?
In the next couple of lines of code we declare the MyPetConstructor() and MyGameConstructor() constructor functions, which both use the MyAnimalConstructor() as a base constructor, and both have a special method only typical to games or pets.
Note the code reuse pattern, an effective way of structuring code, as it makes sense to handle the common properties and methods of similar objects in a single place, rather than duplicating code – both pets and games eat and move, but pets don’t get hunted and games don’t ask food.
Creating a prototype chainAt this point, MyPetConstructor() and MyGameConstructor() doesn’t have access to the prototype object of MyAnimalConstructor(), we have to explicitly set this prototypal inheritance – as mentioned earlier, every function’s prototype property is initialized with an “empty” object, and every instance created by a constructor function “inherits” its prototype object.
In the next line of code we are creating a prototype chain (setting up explicit prototypal inheritance). We are setting the MyGameConstructor() function’s prototype property to an object with Object.create(), which accepts an argument (the first argument of Object.create is always a prototype object), which in this case is the prototype object of the MyAnimalConstructor() function.
So now, the prototype of MyGameConstructor() will point to the prototype of MyAnimalConstructor() – they share the same prototype object, so now every “game” object created with the MyGameConstructor() inherits (rather has access to) all the methods (move, in this case) and properties set on the MyAnimalConstructor() function’s prototype object.
To understand this example better, we haven’t done the same for MyPetConstructor() (see later – “pet” objects don’t have access to the move method).
Now we instantiate a myPet and a myGame object with the MyPetConstructor() and MyGameConstructor(), respectively.
Both myPet and myGame object used the same “base constructor” function MyAnimalConstructor() to get instantiated, but only the myGame object has access to the move method, which was set on the MyAnimalConstructor()‘s prototype, because we explicitly set MyGameConstructor()‘s prototype to point to MyAnimalConstructor()‘s prototype, on which the move method is set.
To prove this, we print myPet‘s and myGame‘s __proto__ property to the web console, and see that only myGame‘s __proto__ property points to the MyAnimalConstructor().
Author: Nandor Persanyi