Prototypal Inheritance

Objectives

  • Explain prototypal inheritance and its purpose.
  • Distinguish the difference between prototypal from classical inheritance.
  • Create and extend prototypes.
  • Explain the difference literal and constructed objects.

Review

  • Describe the difference between functions and methods in JavaScript.

Intro

Prototype-based programming is a style of object-oriented programming in which behavior reuse (known as inheritance) is performed via a process of cloning existing objects that serve as prototypes.

 

This model can also be known as prototypal, prototype-oriented, classless, or instance-based programming. 

DRY: Don't Repeat Yourself

 What do we do when we want to go beyond reusing a value which may just be a primitive or an object containing some key/value data? What if instead we want to clone an object that has behaviors we seek to reuse?

 

Let's look at the Docs!

 

 

Class vs Prototype

The purpose of prototypal inheritance is to offer a modeling object, which contains certain behaviors, to other objects to be prototyped off of, inheriting the model's behaviors. 

 

However, Javascript is not a class-based language, but instead a prototype-based language. 

 

Class:

In Ruby, classes are objects that have unique responsibilities and methods:

  • manufacture new objects
  • define the behavior of the objects they manufacture

Prototypal Inheritance:

Similar to Ruby, Javascript also uses objects, function objects (generally everything in Javascript is an object except primitives), to perform inheritance. However unlike Ruby, Javascript does not have a special function object that can both manufacture a new object as well as define the behavior of the object it creates. Instead, Javascript has two different features, constructors and prototypes, which accomplish these tasks:

  • a constructor function manufactures new objects
  • a prototype property defines the behavior of new objects manufactured by the constructor

Now that we know the key differences between a prototype-based and a class-based language, let's take a deeper dive into the mechanics of a constructor and a prototype.

Take 10 mins to read:
Class vs Prototype

Constructor & Prototype

What exactly is a constructor?

A constructor is just an ordinary function no different than any function you've coded up to this point. However, what does distinguish this function from the rest is when it is used with the new operator.

function Vehicle(color) {
  this.color = color
}

var car = new Vehicle('red')

When we call upon our constructor function with the new operator we are creating a new object instance based off a user-defined object type, in this case Vehicle, or of a built-in object type, such as a String.

 

Essentially, the constructor function is specifying the type of the object instance it creates.

 

This has several implications:

The constructor creates a new object

The constructor sets a special internal constructor property of the object to the constructor function that created it:

 

This means in our example car.constructor === Vehicle.

 

To assert the reference of a constructor, use the instanceof operator. Go into the console of your browser and take five minutes to construct a few objects and then assert its reference. You can do this with a string, array and even your own custom constructor! Here's a String example:

var str = new String("abc") // "abc"

str instanceof String // true
function Foo () {

}

var f = new Foo()

f instanceof Foo // true

The constructor sets up the object to delegate to Vehicle.prototype:

 

Vehicle.prototype.wheels = 4

var car = new Vehicle()

car.wheels // 4

We can see evidence that car inherited the the wheels property from Vehicle's prototype. Let's take an in-depth look in the console to further understand what's going on here:

Here's a diagram showing how the prototype chain works:

A constructed object, in this case car, is set up to delegate properties which haven't been set up yet to take in the values from its prototype. What this means is that, as long as we don't manually define car.wheels, we can use the prototype to redefine the wheels property. Further, any instance created by the Vehicle object can have properties set on their prototype object after the fact!

 

Vehicle.prototype.wheelCount = 8

car.wheels // 8

The constructor calls Vehicle() in the context of the new object:

function Vehicle(color) {
  this.color = color
}

var car = new Vehicle('red')

Context in a nutshell deals with object reference or 'this', which can be called upon to tell you which object you are working with. When we construct a new object the 'this' in our constructor function will refer to the new object instance we are creating. This means that car.color === 'red'. This is what is known as an instance property because it is a property our constructor can define every time it creates a new instance object.

var hyundai = new Vehicle('green')
var volkswagen = new Vehicle('black')
hyundai // Vehicle {color: "green"}
volkswagen // Vehicle {color: "black"}

If you were to define a property with a function this would be known as an instance method. Knowing this, let's use the Vehicle constructor make a couple different cars.

Pop Quiz!

What are the two ways to set properties on an object?


What is one benefit of constructing an object over creating a literal object?

 

Javascript is an object-oriented language, which does not have a traditional class system, instead it is prototype-based.

Almost everything in Javascript is an object and each of these objects contain an internal property called prototype which links the object to the object it is constructed from. This is what defines Javascript as being prototype-based and allows for inheritance.

If we try to access a property on an object that doesn't exist Javascript will search the object's immediate properties, but once it cannot find it, it will continue to search within the object's prototype property. If it can't find it there, it will search within the prototype of that prototype and so on and so forth traversing down the prototype chain until it reaches the core constructor object at the end of the chain. 

With a neighbor or two explain as concisely as possible what is happening line-by-line using all the following keywords: constructor, instance property, prototype, inheritance and prototype chain. On top of that, explain why car has a different value from the first and second times it is printed.

Build a Constructor That... - Independent Practice

With a clear understanding of what it looks like to construct a new object, take 10 minutes to create a constructor function that will allow for two instances and then prototype at least one method onto your constructor. If you can't think of an object you'd like to use as a model for inheritance make a constructor for a Bird or a Country.

Subclasses

Building off of our Vehicle constructor, let's extend Vehicle to make another constructor for hybrid cars.

function Vehicle(color) {
  this.color = color
}

function HybridCar(color) {
  Vehicle.call(this, color)
}

HybridCar.prototype = new Vehicle()

var prius = new HybridCar('white')

prius.color // "white"

On the HybridCar.prototype =... line we are setting the HybridCar's prototype to an instance of Vehicle, so that HybridCar inherits all of Vehicle's properties.

Object.create()

So far we have practiced constructing new objects using the new keyword. However, this is not the only way. Object has a method create which allows us to create a new object with a specified prototype object and its properties.

 

function Vehicle(color) {
  this.color = color
}

function HybridCar(color) {
  Vehicle.call(this, color)
}

HybridCar.prototype = Object.create(Vehicle.prototype)

var prius = new HybridCar('white')

prius.color // "white"

Data Descriptors

  • writable: Whether the concrete value of the property may be changed.
  • configurable: Whether the type of descriptor may be changed, or if the property can be removed.
  • enumerable: Whether the property is listed in a loop through the properties of the object.
  • value: The value of a property.

Accessor Descriptors:

  • get (): A function called with no arguments when the property value is requested using dot notation (i,e: obj.prop).
  • set (newValue): A function called with the new value for the property when the user tries to modify the value of the property using dot notation (i,e: obj.prop = 'new value').

Build a Virtual Farm - Independent Practice

With all the knowledge you've acquired thus far, it's time to put it all together and make a simple app. you'll be creating a virtual farm whose animals can be clicked on to get an alert displaying what sound they make. Open up the starter code to get started!

Here's an example of how a simple animal object should look:

Requirements

  • Must have one FarmAnimal prototype that all other objects extend.
  • 'FarmAnimal' must have name and image instance properties as well as a talk instance method.
  • You should create at least five different animals for your farm.
  • At least two animals must have subclasses. For example, if you create a Cow prototype it would have two types of cow objects extend from it (i.e. Angus & Texas Longhorn).
  • Use vanilla JS or jQuery to create elements based off your FarmAnimal objects and bind them to the DOM. add the class animal to each element.
  • When you click on animal an alert should show display the sound it makes (i.e. mooo!).
  • Each animal element should have position styles, such as left and top, so images aren't stacked on one another.
  • After completing all the above tasks, log your most extended prototypes and have a neighbor decipher the prototype chain without looking at the code. for even more fun, have him/her see if they can recreate the prototyping portion of your code!

ES6 - Same Ol' Inheritance Just With Syntactic Sugar

ECMAScript 2015 also known as ECMAScript 6 (ES6) which is one of the most recently published versions of Javascript. As Javascript evolves, it is becoming more and more object-oriented-like. ES6 only serves to further illustrate this point by introducing "classes" to the language. But wait a second, earlier we said Javascript doesn't have classes?

 

Well, in fact, it still really doesn't. What the new class feature of ES6 brings to Javascript is really just syntactic sugar to make its code look like a traditional class, but in reality, its functionality of inheritance is still being powered by constructors and prototypes. Keeping that in mind let's see what ES6 classes look like!

function Vehicle(color) {
  this.color = color
}

var car = new Vehicle()
class Vehicle {
  constructor(color) {
  this.color = color
  }
}

we go from:

to:

Conclusion

  • What is the difference between class-based and prototype based languages?
  • When would you want to declare a literal object and when would you want to construct an object?
  • Why is using a constructed object better for memory performance?
  • When would you want to implement a "subclass"?
  • What is the purpose of a constructor function?
  • What is the purpose of the prototype property?
  • How does the prototype chain work?
Made with Slides.com