Javascript ‘Classes’ and Prototypal Inheritance

Michael Ries
Code Monkey
7 min readSep 24, 2017

--

If you’re like most people, you learned the basics of object-oriented programming in a language that uses a class-based (or sometimes called classical) inheritance system. These include Ruby, C#, C++, Java, Python, PHP, and others. In these languages, classes are used to define and instantiate objects. Inheritance is achieved by declaring a class to be a subclass of a parent class, enabling the subclass to use methods and properties defined in the parent without duplication. In these systems, it is common to think of classes as blueprints (or templates) and objects as instances created using a class blueprint.

Although the Javascript got the ‘class’ keyword in ECMAScript 2015, it is important to understand that classes in Javascript are quite different from those in classical languages. In this article I hope to explain these differences.

Let’s use Ruby as our classical example.

class Parent; end         # create an empty class
puts Parent.methods.count # 113
a = Parent.new();
puts a.methods.count # 57
puts Parent.instance_of? Object # false
puts Parent.kind_of? Object # true
puts Parent.instance_of? Parent # false

So our class Parent is an object, but is neither an instance of itself nor of an object. In fact, we can see that the Parent class object has significantly more methods than an instance of a Parent. This is because Parent is a special type of object that includes class methods, including #new and #initialize which are needed to create instances of itself.

In Ruby, the only way to create an object is to define a class and call the new method on it. In contrast, Javascript has many ways to create objects. The simplest of these is using {} brackets. Let’s try it out in the chrome console:

In Javascript, objects are just bags of properties with key-value pairs. So in the console above we created a new object with a ‘wheels’ property that has a value of 4, and an engine property of value ‘Internal Combustion’. These are called ‘own properties’. But what is that ‘__proto__’ property and where did it come from?

When an object is created in Javascript, it automatically gets the ‘__proto__’ property, which is a reference to another object. This other object is called the prototype, and can be thought of as the ‘parent’ in the context of inheritance. In this example, the prototype of the car object is Javascript’s ‘Object()’ which is a special object from which nearly all objects descend.

If we want to create a child object of car, we can use Object.setPrototypeOf():

So the vw has a __proto__ property pointing to its prototype , the car, which in turn has the Object() as its prototype. These links form a chain that connects the children through their ancestors and finally terminates at Object(). This is called the prototype chain.

Delegation and the Prototype Chain

Inheritance is achieved by delegating properties up the the prototype chain. Consider some things we might do with our car and vw objects.

// access the own properties
vw.color // 'red'
vw.engine // 'gasoline' -- notice that this shadows the parent
car.engine // 'Internal Combustion'
// access inherited properties of the parent
vw.wheels // 4
// add a method to the parent (Dynamically! After instantiation)
car.go = function() { return 'Vroom!'; }
car.go() // 'Vroom!'
// call methods on the parent that aren't on child
vw.go() // 'Vroom!'
// change the vw to 2 wheels
vw.wheels = 2;
vw.wheels // 2
// notice that this does not change the parent property
car.wheels // 4

It works because whenever you read the property of an object, Javascript first checks for it on the object, but if the property is not found, it checks the prototype for it, and then the prototype’s prototype, etc. until it reaches Object(). It’s a bit like searching a linked-list, if you’re familiar with that. This works for all kinds of properties, including functions.

Constructors and Object.create()

Manipulating the prototype using Object.setPrototypeOf() is generally a bad idea but in this example it illustrates how the prototype chain works. In real world Javascript applications, class inheritance is usually mimicked using constructor functions and the ‘new’ keyword.

// create constructor function for Car
// constructors are capitalized by convention
// own props are initialized in the constructor
function Car() {
this.wheels = 4;
this.engine = "Internal Combustion";
this.go = function() { return 'Vroom!' };
}
// Create constructor for Vw
function Vw() {
Car.call(this); // call the constructor for the parent
this.color = 'red';
}
// set prototype to point at parent
Vw.prototype = Object.create(Car.prototype)
vw = new Vw(); // 'Vroom!'

This works a little differently because the vw prototype is actually a constructor function and not an instance of a car object. When we use the new keyword, the value of this in the constructor points to the object being created. When we write our child constructor, we typically call the parent’s constructor, bound to this. Since this points to the new instance of Wv, the properties being set in the Car constructor will actually be own props of the vw.

The color, engine, wheels and go() properties are copied to each instance of Vw that is created. Since each instance has its own copy of the values, these can be thought of as instance variables. But sometimes we need properties that are shared between all instances, like class variables in other languages. We can achieve this behavior by adding variables to the Car function, which is an object too. Similarly, it is very common to put functions directly on the prototype rather than duplicate them for every instance:

// create constructor function for Car
// constructors are capitalized by convention
function Car() {
this.wheels = 4;
this.engine = "Internal Combustion";
if (Car.hasOwnProperty('population')) {
Car.population++;
} else {
Car.population = 0;
}
this.id = Car.population;
}
Car.prototype.go = function() { return 'Vroom!' }// Create constructor for Vw
function Vw() {
Car.call(this);
this.color = 'red';
}
Vw.prototype = Object.create(Car.prototype)vw = new Vw();

Here we’ve added a population property to Car and used it to set a unique id for each instance. And we moved the go() function to the prototype so that it can be shared by all instances.

This relies on the prototype chain to execute the go() function, exactly as we saw before.

The ES6 class keyword

The class keyword was introduced in ES6 and greatly simplifies the syntax for generating class-like inheritance.

class Car {
constructor() {
this.wheels = 4;
this.engine = "Internal Combustion";

if (Car.hasOwnProperty('population')) {
Car.population++;
} else {
Car.population = 1;
}

this.id = Car.population;
}

// define a method on the prototype
go() {
return 'Vroom!'
}
}
class Vw extends Car {
constructor() {
super(); // calls the constructor on the prototype
this.color = 'red'
}
}

This code behaves exactly like the previous example. The new syntax is easier to read and it’s familiar and comfortable to those of us experienced with classical inheritance. But it’s really just syntactical sugar that uses constructor functions and prototypal inheritance!

Summary

  • In classical inheritance, the class is a special type of object that is responsible for creating instances of itself. These classes are the only way to create objects.
  • In Javascript, any function can create an object, which are simply bags of properties — they do not need a blueprint. Inheritance of properties by a child from an ancestor is achieved by searching up the prototype chain.
  • Javascript prototypes are themselves instances, and any object can be a prototype, not just special class objects.
  • The ES6 class keyword enables very readable and familiar syntax for building class-like inheritance, but it’s really prototypal inheritance in disguise.

Parting Words

For many people learning Javascript, the inheritance system feels unnecessarily complicated, confusing, and… well, broken. If you’re one of these people, you may be surprised that some serious Javascript developers felt that the addition of the ES6 class syntax was a step in the wrong direction. Why?

Some argue that it fools beginners into thinking that Javascript has classes like other languages with similar syntax. This can lead to confusion and bugs. Others just say it’s just unnecessary.

Personally, I feel the best argument against it is that it puts your mind in a place where you tend to formulate solutions based on classical inheritance, because that’s what you’re familiar with.

In classical languages like Ruby, you use classes and inheritance because they are the only tools available for composing objects. In Javascript, you can compose objects in other ways, giving you the flexibility to come up with better solutions. I plan to discuss this in my next post.

Also, please check out my earlier posts:

Understanding Closures in Javascript

Form Validation in React

OAuth in React/Redux Applications

--

--

Michael Ries
Code Monkey

Solving complex problems one simple problem at a time.