May 2020

JavaScript ES6: The Basics of Classes

JavaScript ES6 Classes are used to set up inheritance and to create objects, and is meant as a solution for JavaScript’s prototypal inheritance. In the examples below you’ll see how messy and complex it is to set up prototypal inheritance and how you can use ES6 Classes to make understanding and implementing inheritance much easier!

The code below is a basic example of how to create objects using a constructor in JavaScript ES5.

//ES5 Basic object creation
// Constructor object
function Car(options) {
  this.title = options.title;
}

// Add a method to the constructor (constructor function)
Car.prototype.drive = function() {
  return 'vroom!';
}

// new keyword on the Car constructor to make a new car
const car = new Car({ title: 'Focus' });

console.log(car); // {"title":"Focus"}
console.log(car.drive); // vroom!

In the code, you’ll see that we are using the ‘prototype’ keyword to create a function on our Car constructor. 

I’m not going to try to explain exactly what the prototype keyword actually does because if you haven’t worked with it much *cough*like me*cough* then it’s difficult to explain. 

So don’t worry about the ‘prototype’ keyword too much as ES6 Classes will be much simpler to get a grasp of.

Let’s expand on the example above by adding an object that will inherit Car so we can set up prototypal linking and then we’ll refactor it using ES6 Classes to show you how much easier it is.

//ES5 Prototypal Inheritance
// Constructor object
function Car(options) {
  this.title = options.title;
}

// Add a method to the constructor (constructor function)
Car.prototype.drive = function() {
  return 'vroom!';
}

// Toyota constructor which will inherit from the Car constructor
function Toyota(options) {
  this.color = options.color;
}

const toyota = new Toyota({ color: 'red', title: 'Daily Driver' });

console.log(toyota); // {"color":"red"}

You’ll see that when we console.log() toyota we only get the color as an output.

Since Toyota is a type of car, we want to set up our Toyota constructor to inherit all the properties and methods of our Car constructor.

// Constructor object
function Car(options) {
  this.title = options.title;
}

// Add a method to the constructor (constructor function)
Car.prototype.drive = function() {
  return 'vroom!';
}

// Toyota constructor which will inherit from the Car constructor
function Toyota(options) {
  // Execute an initialisation that occurs in Car
  Car.call(this, options);
  this.color = options.color;
}
// Duplicate of Car prototype
Toyota.prototype = Object.create(Car.prototype); 

// Add a constructor
Toyota.prototype.constructor = Toyota;

// Now we can add a method to Toyota's prototype
Toyota.prototype.honk = function() {
  return 'beep';
}

const toyota = new Toyota({ color: 'red', title: 'Daily Driver' });

console.log(toyota); // { title, "Daily Driver", color:"red" }
console.log(toyota.honk()); // beep
console.log(toyota.drive()); // vroom

As you might have guessed, writing all that out isn’t fun. There’s so much code for so little functionality, it’s messy, I want it out of my life.

So with ES6 Classes, we’re going to skip having to set up the constructor function, worrying about all the inheritance and writing out the ‘prototype’ keyword all over the place. 

To write a Class, we use the ‘class’ keyword, followed by the name of the class, followed by curly braces. We can then create an instance of that class inside a variable.

// Create the Car class object
class Car {
  // empty 
}

// Create an instance of Car in the car variable.
const car = new Car();

console.log(car); // Car class is empty, so car variable is also empty

Next, to add a method to our class we use the enhanced object literal syntax. That sounds scary but in this case, it’s really just writing a function without the ‘function’ keyword. Let’s recreate our drive method from earlier.

// Create the Car class object
class Car {
  // drive method
  drive() {
      return "vroom";
  }
}

// Create an instance of Car in the car variable.
const car = new Car();

console.log(car.drive()); // vroom

Next, we’re going to do some initialisation within the class. To do this we use a method called ‘constructor()’, which runs whenever we use the ‘new’ keyword on that specific class.

// Create the Car class object
class Car {
  constructor() {
      // I initiate when a new Car() is created!
  }

  drive() {
      return "vroom";
  }
}

// Create an instance of Car in the car variable.
const car = new Car();

We are then going to enter in a title in ‘new Car();’ which will pass title onto the constructor method.

// Create the Car class object
class Car {
  constructor(options) {
      this.title = options.title;
  }

  drive() {
      return "vroom";
  }
}

const car = new Car({ title: 'Toyota' });
console.log(car); // { title:"Toyota" }

Now that we have our Car class set up, we can use the same class syntax we used to create Car to create the Toyota class.

// Create the Car class object
class Car {
  constructor(options) {
      this.title = options.title;
  }

  drive() {
      return "vroom";
  }
}

// Create the Toyota class object
class Toyota {
  constructor(options) {
      this.color = options.color;
  }

  honk() {
      return "beep";
  }
}

// Create an instance of Car in the car variable.
const car = new Car({ title: 'Toyota' });
console.log(car.drive()); // vroom
console.log(car); // { title:"Toyota" }

// Create an instance of Toyota in the toyota variable.
const toyota = new Toyota({ color: 'red' });
console.log(toyota.honk()); // beep
console.log(toyota); // { color:"red" }

Remember, constructor() gets initiated whenever we create a new instance of a class.

Now that Toyota is set up, we want it to inherit the configuration that happens in Car. We’ll also want a separate constructor for Toyota so we can do some custom configuration that we want on Toyota but doesn’t happen in Car.

You’ll remember that in ES5 when setting up inheritance we had to dedicate a few lines to the set up along with the use of a lot of keywords. In ES6, we only have two small additions to make.

On the Toyota class, we simply put ‘class Toyota extends Car’ which will allow Toyota to use all of Car’s methods. 

In Toyota’s constructor(), we’ll call super() to get Car’s properties. So what’s super()? super() calls the constructor of the class that was used after the ‘extends’ keyword. So in our example, super(options) translates to Car.constructor(options).

class Toyota extends Car {
  constructor(options) {
      super(options); // Car.constructor(options)
      this.color = options.color;
  }

  honk() {
      return "beep";
  }
}

And the finished code in its entirety;

//ES6 Classes
// Create the Car class object
class Car {
  constructor(options) {
      this.title = options.title;
  }
    
  drive() {
      return "vroom";
  }
}

// Create the Toyota class object
class Toyota extends Car {
  constructor(options) {
      super(options); // Car.constructor(options)
      this.color = options.color;
  }

  honk() {
      return "beep";
  }
}

// Create an instance of Car in the car variable.
const car = new Car({ title: 'Toyota' });
console.log(car.drive()); // vroom
console.log(car); // { title:"Toyota" }

// Create an instance of Toyota in the toyota variable.
const toyota = new Toyota({ color: 'red', title: 'Daily Driver' });
console.log(toyota.honk()); // beep
console.log(toyota.drive()); // vroom
console.log(toyota); // { title, "Daily Driver", color:"red" }

That’s the basics of JavaScript ES6 Classes! Using two new keywords, ‘class’ and ‘extends’, we can write much cleaner and legible code compared to ES5 where we had to use ‘prototype’.


Continue Reading

  • December 2017

    Understanding SSL Certificates

    SSL certificates are not optional any more, they are critical. Here we help you get a better understanding of what exactly they provide.

  • April 2020

    CodePen Challenge: Handling User-Uploaded Images

    In this week's Challenge, we start with a set of very different user-uploaded avatars and it's our job to do something with them to bring them together nicely.

  • September 2019

    Next-gen Images: Page Speed’s New Best Friend

    Converting your images to a next-gen image format, like WebP, is one of the best ways to improve the user’s experience and page speed on your website.

  • October 2021

    CodePen Challenge: Terrible Text Fields

    Be wary, a tormented ghost has possessed the text field in this CodePen. Type into the text field, if you dare, and experience the spirit's wrath!

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now