I'm not drunk, but I could be.

03/27/2016

Github Cat
Sample image

In my last post, we talked a little about Ruby classes and how they help me get drunk. We're going to compare that a bit with JavaScript constructor functions and prototypes.

On the surface, these things look extremely similar. We can make a JavaScript constructor function that provides the same information as my Ruby class**:

  
    function Drunk(name, numberOfDrinks){
    this.person = name;
    this.numberOfDrinks = numberOfDrinks;
    }

    var i = new Drunk("aarthi", 2);
  

**For simplicity's sake, I provided the information for numberOfDrinks instead of asking the user to input it with a prompt().

Here, I've created a new constructor function Drunk, and a new variable i. This variable is now an object that calls on the Drunk constructor function. When we console.log(i), we get:

Drunk { person: 'aarthi', numberOfDrinks: 2 }

So far so good. The constructor function in JavaScript looks like the initialization method in Ruby, and object i looks to have the same properties.

Now let's check out what would happen if I wanted to haveAnother:

  
      Drunk.prototype.haveAnother = function(){
        if (this.numberOfDrinks < 4) {
          this.numberOfDrinks ++;
          console.log("You've had " + this.numberOfDrinks + " drinks.");
        }
        else {
          console.log("Go to bed.");
        }
      }
    
  

Woah! Prototype?! What in the world is that?

Prototypes are JavaScript's way of figuring out classes and inheritance. Here, we're saying that all Drunks that are created will be able to haveAnother, because Drunk.prototype is their parent. We can check this using

i.__proto__ === Drunk.prototype

Which returns true. Why would we want to use prototypes instead of defining haveAnother as a property of a Drunk? Because each time we create a Drunk, we want them to be able to haveAnother. If we define this function within the Drunk constructor function, it will be recreated for every new Drunk. However, if we define it as a prototype, haveAnother is created only once, and is inherited by all Drunks... all because Drunk.prototype is their parent.

Let's take this idea of inhertiance a step further. All persons can drink, but only persons over 21 should drink in the US. We can create a Person using:

  
    function Person(name, age, numberOfDrinks){
      this.person = name;
      this.age = age;
      this.numberOfDrinks = numberOfDrinks;
    }

    Person.prototype = new Drunk();

    Person.prototype.constructor = Person;
  

The first statement creates the Person with a name, age, and numberOfDrinks. The second ensures that a Person constructor is created, and that each Person is an instance of Drunk. The third ensures that Persons know they are Persons. Now, any Person will be able to inherit Drunk functions. Let's rework our haveAnother function so we don't get any children drunk.

  
Drunk.prototype.haveAnother = function(){
  if (this.age < 21){
    console.log("Get out of here, kid.")
  }
  else if (this.numberOfDrinks < 4) {
    this.numberOfDrinks ++;
    console.log("You've had " + this.numberOfDrinks + " drinks.");
  }
  else {
    console.log("Go to bed.");
  }
}

Now if we create a new child object** and i object:


  var child = new Person("bobby", 13)

  var i = new Person("aarthi", 27, 2)

**Cool side note: JavaScript allows you to have optional arguments. Because I don't want child to start off with any numberOfDrinks, I can just omit the parameter entirely instead of putting 0.

And try to make child.haveAnother(), we return "Get out of here, kid.", even though i.haveAnother() will still send me down a drunken road.

We can see this even clearer if we check out the return values of the following:
  
child.__proto__ === Drunk.prototype;
//returns false
child.__proto__ === Person.prototype;
//returns true
child instanceof Drunk;
//returns true

Here we find that child is an instantiated Drunk object. It is a Person and an instance of a Drunk.

If we checked out the inheritance in Ruby, we'd find that all methods of the Object Class were inherited by objects in the Drunk Class. They have all these secret, internal methods that Ruby gives them. In JavaScript, we can define prototypes directly because all of their methods are exposed. We can manipulate them and define each and every method that we want the prototype to exhibit.

This concept can be a little confusing. Check out the following resources for a little more information:

The best way to think about this is that JavaScript is really flexible. It's a language that might be a bit more difficult to read than Ruby, but allows you to manipulate functions and prototypes on their fundamental method levels.