Start tracking your progress
Trailhead Home
Trailhead Home

Work with Classes

Work with Classes

Learning Objectives

After completing this unit, you’ll be able to:

  • Explain what’s different about how you create and invoke classes in ES6+.
  • List the commonly used members of a class.
  • Distinguish between a base and derived class.

Pile of rubber ducks.

If It Looks Like a Class…

Prior to ES6, if you wanted to create a class in JavaScript, you used prototypes to do something similar to this:

function Animal(name) {
  this.name = name;
}
      
Animal.prototype.printName = function() {
  console.log(this.name);
}

In that example, a prototype-based constructor function named Animal was created. An uppercase “A” was used in the function name and arguments were assigned to the this keyword. This is the only clue that let’s other developers know that Animal is not just another function. If you wanted to instantiate the class and call the printName function, you would do it like this:

let duck = new Animal('duck');
duck.printName();  // Displays "duck"  

If you are coming from another language, then you are probably used to class-based inheritance. In a nutshell, JavaScript does not work like that. In an attempt to make JavaScript at least appear to work like a class-based language, ES6 introduced the class keyword. Using this new syntax means that the Animal class can now be defined like this:

class Animal {
  constructor(name) {
    this.name = name;
  }
    
  printName() {
    console.log(this.name);
  }
}  

What is important to know is that even though the class keyword is used, the underlying object created is still a function. Executing the following code would show “function” and not “class” in the console as the type.

console.log(typeof Animal);  // Display "function"

Instantiating and using methods from the class works exactly the same as it did for constructor functions. Well, kind of. Using the new keyword was optional for ES5 constructor functions, but now is required. If you try to leave off the >new keyword when working with classes, a TypeError will be thrown.

Another difference is that function declarations can be hoisted. In other words, you can call a function that has yet to be declared. Classes do not allow this sort of thing. A class can only be accessed after its definition is evaluated. 

Classes can contain the following kinds of members.

Member
Description
Example
Constructor
The constructor is executed automatically when creating a new instance of the class. It guarantees that an initialization function is always called. This helps maintain a valid state for the class. But you don’t have to create a constructor. If one is not included, then the JavaScript engine creates an empty one for you.
constructor(name) {
  this.name = name;
}

Static Methods
Static methods are not part of any instance of the class, meaning that you can refer to these methods without referring to an instance. The concept of static class members is not new to ES6, but the static keyword is. Prior to ES6, you had to put any methods you wanted static in the constructor. Now you can put them wherever you want in the class and just use the static keyword.
static methodName() {
  return 'something';
}

Prototype Methods
These methods do not include the static keyword and must be referenced with an instance.
printName() {
 console.log(this.name);
}

Getters and Setters
These accessor functions work just like object literals and work the same as they did in ES5. Essentially you just put the get and set keywords in front of the property name. If you define a getter without a setter, then the property becomes read-only.
get area() {
  return this.height * this.width;
 }

set area(value) {
  this.area = value;
}

The most important thing to remember is that even though ES6 classes look like traditional object-oriented classes, they are not. Even with the new class keyword, they are still based on JavaScript’s prototypal inheritance. 

Speaking of Inheritance

Since we mentioned inheritance, you may be wondering how that works with the new syntax. You will be happy to know that ES6 classes make inheritance much easier and more intuitive. 

Classes come in two flavors: base classes and derived classes. The difference is the extends keyword. Derived classes (also known as subclasses) have them, and base classes don’t. Take, for example, the following base class named Parent. 

class Parent {
  constructor(name) {
    this.name = name;
  }
      
  getName() {
    return this.name;
  }
}  

Assume you needed to create a subclass named Child that extends the functionality available in the Parent class. It might look something like this:

class Child extends Parent {
  constructor(name) {
    super(name);
  }
        
  getMessage() {
    return 'Hello ' + super.getName();
  }
}
      
let someone = new Child('person');
console.log(someone.getMessage());     // Displays "Hello person"  
  

Copying all that code into CodePen and saving it results in the phrase “Hello person” printed to the console. The extends keyword in the Child class definition tells you it’s a derived class. 

Also notice the use of the super keyword, which allows you to reference the parent constructor and the method definitions from the Base class. Whenever you see the super keyword, you know you are in a derived class and referring to the base class.

Tell Me More

  • Although commas are used to separate method definitions in objects, they are not allowed in classes.
  • Classes can also be defined using expressions:
const myAnimal = class Animal {
  constructor(name) {
    this.name = name;
  }
          
  printName() {
    console.log(this.name);
  }
}  
  

And the printName method can be accessed like this:

let duck = new myAnimal('duck');
duck.printName();  // Displays "duck"  
  

Resources

Details of the object model

Defining classes

Class expression

Static keyword

Object-oriented JavaScript: A Deep Dive into ES6 Classes

Classes in ECMAScript6 (final semantics)

retargeting