Lesson Tuesday

We've already covered ES6 support for modules (which are implemented with import and export). In this lesson, we’ll go over ES6’s native support for classes. Classes 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

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:

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

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

Here we create a Triangle constructor and then a prototype for that constructor. Let’s update this code to use the new class keyword.

src/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.

Using Variables in ES6 Classes

There is one important thing to note about ES6 class syntax. Variables cannot be scoped to the class itself. The following will not work:

class Triangle {
  let variableScopedToClass = 0;
}

Scoping a variable inside a class (regardless of whether using var, let or const) will result in the following error: Parsing error: Unexpected token. It's not a very helpful error, which is why we mention it here. Students coming from other languages (such as C# or Ruby) may expect that JS will also have class variables, but that is not the case.

Instead, variables should always be scoped to methods inside the class (including the constructor). For instance, this is fine:

class Triangle {
  ...

  checkType() {
    let variableScopedToMethod = 0;
  }    
};

The people behind ES6 made a conscious choice not to include class variables. The reasons for this are beyond the scope of this lesson; for now, it's enough to say that class variables simply don't fit JavaScript's prototypical inheritance model. In any case, variables should be scoped as tightly as possible as a best practice, so avoiding class variables (and globals) is always a good idea.

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