Wednesday 14 January 2015

JavaScript Inheritance and the Prototype

You know inheritance, right? You know how in Java, for example, you can have one class inherit another and automatically get all the methods and variables of the parent class?
public class Mammal{
    public void breathe(){
        // do some breathing
    }
}
public class Cat extends Mammal{
    // now cat too can breathe!
}
Well, in Javascript, we have the same thing, just different. For starters, we don’t even have classes! Instead, we have something called the prototype. Here’s how we write the equivalent of the above Java code in Javascript
function Mammal(){
}
Mammal.prototype.breathe = function(){
    // do some breathing
}
function Cat(){
}
Cat.prototype = new Mammal()
Cat.prototype.constructor = Cat
// now cat too can breathe!
What’s this prototype? That’s just a bunch of gibberish!
Javascript is different from traditional object-oriented languages in that it usesprototype inheritance. In a nutshell, prototype inheritance in Javascript works like this:
  1. An object has a number of properties. This includes any attributes or functions(methods).
  2. An object has a special parent property, this is also called the prototype of the object(__proto__). An object inherits all the properties of its parent.
  3. An object can override a property of its parent by setting the property on itself.
  4. A constructor creates objects. Each constructor has an associated prototypeobject, which is simply another object.
  5. When an object is created, it’s parent is set to the prototype object associated with the constructor that created it.
Okay! Now that you understand everything there is to know about prototype inheritance, let’s look at our Cat example more closely and break it down.
First, we create a constructor for Mammal
function Mammal(){
}
At this point, Mammal already has an associated prototype
Mammal.prototype
// {}
Let’s create an instance
var mammal = new Mammal()
Now, let’s verify the second law of prototype inheritence(it’s just the second bullet from the list)
mammal.__proto__ === Mammal.prototype
// true
Next, we add the breathe function to the prototype of Mammal
Mammal.prototype.breathe = function(){
    // do some breathing
}
At this point, mammal the instance can breathe
mammal.breathe()
because it inherits from Mammal.prototype. Next,
function Cat(){
}
Cat.prototype = new Mammal()
Cat constructor is created and we set Cat.prototype to a new instance of Mammal. Why do we do this?
var garfield = new Cat()
garfield.breathe()
because now any cat instance inherits Mammal and will therefore be able to breathe as well. Next,
Cat.prototype.constructor = Cat
Ensures that cats know that they are cats:
garfield.__proto__ === Cat.prototype
// true
Cat.prototype.constructor === Cat
// true
garfield instanceof Cat
// true
Each time you create a new instance of Cat, you create a 2-level chain, in thatgarfield is now parented by Cat.prototype which, since it is an instance ofMammal, is in turn parented by Mammal.prototype.
Now, guess who’s the parent of Mammal.prototype? Yeah, you guessed it,Object.prototype. So actually, it’s a 3-level chain
garfield -> Cat.prototype -> Mammal.prototype -> Object.prototype
You can add properties to any of garfield’s parents, and garfield would magically gain those properties too, even after garfield has already been created!
Cat.prototype.isCat = true
Mammal.prototype.isMammal = true
Object.prototype.isObject = true
garfield.isCat // true
garfield.isMammal // true
garfield.isObject // true
You can ask whether he has a given property
'isMammal' in garfield
// true
and you can also distinguish between own properties vs inherited properties
garfield.name = 'Garfield'
garfield.hasOwnProperty('name')
// true
garfield.hasOwnProperty('breathe')
// false

No comments:

Post a Comment