Lesson Tuesday

In this lesson, we’ll go over ES6’s native support for classes and modules. These changes make JavaScript more accessible and easier to read from an object-oriented (OO) perspective. However, they don’t fundamentally change the way JavaScript works.

The class Keyword

Let’s start with classes. Classes are a cornerstone of many OO languages, including Ruby, Java and C#, but JavaScript didn’t include support for classes until ES6.

Let’s look at how we can refactor our code to use the class keyword. To do this, we'll reference the back end code for triangle tracker again:

js/triangle.js
function Triangle(side1, side2, side3) {
  this.side1 = side1;
  this.side2 = side2;
  this.side3 = side3;
}

Triangle.prototype.checkType = function() {
  //Function body goes here.
};
exports.triangleModule = Triangle;

Here we create a Triangle constructor and then a prototype for that constructor. (The exports line is included because we’ll be refactoring this in the second part of the lesson.) Let’s update this code to use the new class keyword.

js/triangle.js
class Triangle {
  constructor(side1, side2, side3) {
    this.side1 = side1;
    this.side2 = side2;
    this.side3 = side3;
  }

  checkType() {
    //Function body goes here.
  }    
};

Our class Triangle now contains both the Triangle constructor and all its prototypes. (Note that all code is now inside the curly braces for class Triangle.) We no longer need to specify the prototype when we declare the checkType() function. In fact, this code looks very similar to how we might construct a class in other OO languages such as Ruby.

However, it’s important to remember that JavaScript classes are mostly syntactic sugar. Syntactic sugar is a term developers use for added functionality in a programming language that makes it easier to write and read.

JavaScript classes are syntactic sugar because they don’t operate in the same way that classes do in other OO languages such as Ruby. The biggest difference is that JavaScript doesn’t directly use classical inheritance. Instead, JavaScript uses what’s commonly referred to as prototypal inheritance.

Inheritance in JavaScript

Classical inheritance simply means that one class inherits from another class. While classical inheritance has its advantages, it has one major disadvantage: when one class inherits from another, it inherits everything. The coder Joe Armstrong explains this problem with an apt metaphor: “You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.”

With prototypal inheritance, objects inherit from other objects. Prototypal inheritance is an advanced topic beyond the scope of this lesson, but you should be aware that it can be used to make inheritance more nuanced. In other words, if you want a banana, you’ll just get a banana.

The new ES6 functionality fakes classical inheritance by building it on top of prototypal inheritance. In other words, we can use this functionality to have one class inherit from another. We use the extends keyword to do this:

class Shape {
  ...
}

class Triangle extends Shape {
  ...
}

You won’t be expected to have one class inherit from another on the code review, but you’re encouraged to explore inheritance further on your two-day project. At the very least, you should be able to create classes that don’t incorporate inheritance on the code review.

ES6 Modules

ES6 has also added new support for modules. Over the last few days, we’ve used the following:

function Triangle(side1, side2, side3) {
  ...
}

Triangle.prototype.checkType = function() {
  ... 
};
exports.triangleModule = Triangle;

This exports the Triangle constructor and its prototypes into a triangleModule. We then add a require statement to any files where the triangleModule is needed, like this:

var Triangle = require('./../js/triangle.js').triangleModule;

Now we can refactor this, too:

export class Triangle {
  constructor(side1, side2, side3) {
    this.side1 = side1;
    this.side2 = side2;
    this.side3 = side3;
  }

  checkType() {
  //Function body goes here.
  }    
};

Here we add the export keyword to make the Triangle class available to other files. Then, in any file where we need Triangle, we can do the following:

import { Triangle } from './../js/triangle.js';

If we wanted to inherit multiple classes from triangle.js, our import statement would look like this (providing that we have export statements for each of these shapes):

import { Triangle, Rectangle, Circle } from './../js/triangle.js';

For the Friday code review, make sure to use ES6 syntax for your modules. Note that the require statements in your gulpfile.js should not be changed in this way. Instead, you can use this syntax for your backend, interface, and test .js files.

While ES6’s implementation of classes and modules is mostly syntactic sugar, utilizing these features can make your code cleaner, more organized, and easier to read!