Prototype, Inheritance, & You

Ryan Kendig
5 min readFeb 2, 2021
not this type of inheritance, but sort of.

Inheritance is an important aspect of any programming language as you use it to scale up an application. If JavaScript isn’t your first programming language, odds are you are familiar with the concept of Class. If not, a Class is a template you create for an object. You create methods and attributes in that template and then use it to create future instances of that Class. The idea kind of exists, but formally there are no classes in JS. JavaScript is not as much a class-based language as it is a prototype-based language. But what does that mean? Put on your denim jumpsuit, grab our monkey wrench, and we’ll take a peek under the hood.

Let’s start with a basic object:

let player = {}
player.name = 'Ryan'
player.guitarSkill = 0
player.learnScales = function (amount) {
console.log(`${this.name} is learning scales.`)
this.guitarSkill += 1
}
player.strumming = function (amount) {
console.log(`${this.name} is strumming the guitar.`)
this.guitarSkill += 1
}

So we have an object and a couple pieces of logic, but this only applies to one player (me). That’s not super helpful for anyone that isn’t me, but with a few small tweaks, we could create a constructor function which is responsible for “constructing” new objects. Here’s the same example but as a constructor function:

function Player (name, guitarSkill) {
let player = {}
player.name = name
player.guitarSkill = guitarSkill
player.learnScales = function (amount) {
console.log(`${this.name} is learning scales.`)
this.guitarSkill += 1
}
player.strumming = function (amount) {
console.log(`${this.name} is strumming the guitar.`)
this.guitarSkill += 1
}
return player
}
const slash = Player('Slash', 6)
const jimi = Player('Jimi Hendrix', 10)

A constructor function allows us to create new instances of the Player object simply by passing values for the keys we created initially — name & guitarSkill. So we have these shared methods that are relatively generic for our guitar player Class. If we know we’re going to use these methods often, we can refactor our guitar player object by saving the shared methods to another function. By doing this refactor, we have a cleaner Player object and we’re saving memory in the process.

const practice = {
learnScales(amount) {
console.log(`${this.name} is learning scales.`)
this.guitarSkill += amount
},
strumming(amount) {
console.log(`${this.name} is strumming the guitar.`)
this.guitarSkill += amount
}
}
function Player(name, guitarSkill) {
let player = {}
player.name = name
player.guitarSkill = guitarSkill
player.learnScales = practice.learnScales
player.strumming = practice.strumming
return player
}
const slash = new Player('Slash', 6)
const jimi = new Player('Jimi Hendrix', 10)

Now that we’ve moved the shared methods into their own object and we reference them in our Player object, we essentially created built-in methods that can be used in any instance of a Player we create. We call the shots around here, JavaScript. We are the revolution.

Well almost. This very idea is also built into JavaScript in the form of a property known as Prototype.

Prototypes are the mechanism by which JavaScript objects inherit features from one another.

Every function in JavaScript has a prototype property which is basically a pre-loaded object inside that function. Here we can attach methods and properties to the function which enables all subsequent objects created to inherit from our Player object. Here is what our Player object prototype looks like at the moment:

To break down what possibly looks like hieroglyphics above, the Player Object prototype object first shows the attributes that you created in the constructor function (name, guitarSkill). Then, there’s an additional prototype object within a prototype object (__proto__ or dunder proto) that has more methods already defined. What happens if we were to call the ‘valueOf’ method on an instance of our Player Object?

The valueOf() method returns the primitive value of the object. What’s import about this is the process of how we return the information. The browser initially checks to see if the ‘john’ object has a valueOf() method defined on its constructor ‘Player()’ which is does not. Then it checks if the ‘john’ prototype object has the valueOf() method on it. Again, it does not. Finally the browser checks if ‘john’s prototype object’s prototype object has the method and finally, it does. It’s important to distinguish that calling the valueOf() method involves walking up the chain rather than copying attributes from one object to the next in the prototype chain.

So we know at a fundamental level what prototype is and we built a very simple version of it ourselves. How do we take our version and bolt it onto the prototype object that gets created automatically? Surprisingly easy. Just chain ‘prototype’ onto our Player object and write the function we want to bolt on.

Player.prototype.shredSolo= function() {
console.log(`${this.name} is shredding that solo!`)
}

You’ll now see a your custom ‘shredSolo’ method included within the prototype object. You can call this method on any instance of this object that you create thereafter.

JavaScript is a prototype-based language. In order to provide inheritance, objects can have a prototype object, which acts as a template object that it inherits methods and properties from.

What we’ve built in this article is aligned with what’s known as the pseudoclassical pattern and is one of four instantiation patterns available in JavaScript. The pattern uses a constructor function and the ‘new’ operator to create new instances, then uses the prototype property so that those instances can inherit properties and methods. Although classes are not specifically built into JavaScript, this is one way to create an inheritance chain between objects.

--

--

Ryan Kendig

Player of guitars and games. Learning to code one curly brace at a time.