May 17th, 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

  • Bubbling beer svg

    June 13th, 2020

    CodePen Challenge: Bubbling

    This month we explore concepts that help us get our animation juices flowing. We are also provided resources to help us learn GSAP or level up your GSAP skills.

  • September 25th, 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.

  • April 29th, 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.

  • April 8th, 2020

    CodePen Challenge: Hero

    The goal here was to create a hero with at least one image. I decided to demonstrate how an image overlay can improve text readability. To show how well this works across a wide array of images, a reload button is included which keeps reloading new images from picsum!

Your browser is out-of-date!

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