Classes in Javascript

Creating pseudo classes in JavaScript using prototypes

JavaScript doesn’t follow a classical inheritance model (although it can be made to do so), but instead uses a prototypal inheritance model at its core. See my introduction post on prototypes and objects if your not clear how this works.

What this means is that instead of having classes inheriting from other classes you have simply objects inheriting from objects via an internal link called its prototype. A “class” in JavaScript is typically nothing more than a function.

Let’s pretend we have a game, with a base Actor class that provides properties used by the different types of objects in the game. We’ll also have a Player class and a Monster class that inherit from that and add their own properties.

In that setup, the Actor and Player classes might look like this:

// Our base class
function Actor() {
  this.positionX = 0;
  this.positionY = 0;
}

// Define a method on Actors prototype so it can be inherited
Actor.prototype.move = function(x, y) {
    this.positionX = x;
    this.positionY = y;
}

// Create a new player class that will inherit from Actor
function Player() {
  Actor.call(this); // Calls Actor, creating local instances of its properties.
  this.health = 100; // Add a unique var on Player instance.
}

At this point, if we create a new player by calling new Player, it will have 3 variables defined on it. The two position variables from Actor and one defined by Player, But if you try to call player.move(x, y), JavaScript will give you an error saying that it’s not a function. It’s missing from the Player instance.

In order for our players to inherit the move method, our prototype chain needs to have Player inheriting from Actor.

Our first attempt to do this might be to try to set the prototype directly:

// This will not work right.
Player.prototype = Actor.prototype;

However, this would mean that anything you do on the Player prototype would would affect the Actor prototype (because it’s a reference to the same object). If you define a method on Player.prototype, it will actually be created on the Actor.prototype, which will affect all other things that inherit from Actor.

Our intent is to have Player inherit from Actor, while still maintaining its own prototype that we can make changes to and that its children could inherit from. To do this, Player must have its own prototype while its prototype’s prototype is Actor. We might try doing it like this:

Player.prototype.prototype = Actor.prototype; // Won't work

The problem with that is we can only affect an object’s direct prototype. Because we can’t modify the prototype’s prototype we need to create an inheritance chain using the new operator.

Player.prototype = new Actor();

This is creating a new instance of Actor, whose prototype is Actor’s prototype. It has everything that Actor has, but modifying it will modify the instance, and not Actor’s prototype. This is good, but the problem is that this expression calls Actor’s constructor. The constructor is nothing more than the part of the “class” function that is executed when we create a new instance of it.

If your constructor has side effects, such as modifying an external state, you don’t want this to occur at the time you’re creating your new Player class – only at the time you’re creating new instances of Player.

For example, let’s say that the Actor constructor logged stats about how many actor instances were created:

var stats = {numActorsCreated: 0};

function Actor() {
  stats.numActorsCreated++; // I'm going to run when a new instance is created.
  this.x = 0;
  this.y = 0;
}

function Player() {
  Actor.call(this);
  this.health = 100;
}

Player.prototype = new Actor();

var p = new Player();

console.log(stats.numActorsCreated);  // 2

Because we created a new Player prototype using new Actor(), we have prematurely incremented our stat before any actor instances were actually created.

We can workaround this by creating a temporary empty constructor function that we can use with new. We can set its prototype to Actor’s prototype, and use a new instance of it as Player’s prototype:

var stats = {numActorsCreated: 0};

function Actor() {
  stats.numActorsCreated++;
  this.x = 0;
  this.y = 0;
}

function Player() {
  Actor.call(this);
  this.health = 100;
}

function Temp() {};
Temp.prototype = Actor.prototype;
Player.prototype = new Temp(); // No side effects

var p = new Player(); // calls our Actor constructor

console.log(stats.numActorsCreated);  // 1

We now have a prototype chain that links our new player p to Player, and then to Actor. That works, but if we want to repeat this for other classes it could get pretty verbose. It might be easier to create a reusable function:

function inherit(parent) {
  function Temp() {}
  Temp.prototype = parent.prototype;
  return new Temp();
}

function Actor() {
  this.x = 0;
  this.y = 0;
}

function Player() {
  Actor.call(this);
  this.health = 100;
}

Player.prototype = inherit(Actor);

function Monster() {
  Actor.call(this);
  this.health = 10;
}

Monster.prototype = inherit(Actor);

That’s a simple example of using prototype for classical inheritance in JavaScript. Thanks to additions to the JavaScript language like Object.create(), inheritance has gotten even easier.

If you want to learn more about how that can simplify your code, take a look at my post on inheritance using Object.create().