Classes page

Learn about JavaScript classes

NOTE: This section is currently under development. There are no exercises yet.

Overview

In JavaScript, a class is a structured way to define what you saw in the previous section - prototype-based constructor functions. Before ECMAScript 2015, you would create constructor functions as follows:

//prototype way
function ParkEmployee(name) {
  this.name = name;
}

ParkEmployee.prototype.sayHi = function() {
  console.log("Hi, my name is " + this.name);
}

let raptorGuy = new ParkEmployee("Owen");
raptorGuy.sayHi();
//Logs "Hi, my name is Owen"

In ECMAScript 2015, classes are available as syntactic sugar over the existing prototype-based constructor functions. You can write the previous example with class as follows:

class ParkEmployee {
  constructor(name){
    this.name = name;
  }
  sayHi(){
    console.log("Hi, my name is " + this.name);
  }
}

let raptorGuy = new ParkEmployee("Owen");
raptorGuy.sayHi();
//Logs "Hi, my name is Owen"

Getters, Setters and Method Definitions

Classes initially only allowed getters, setters and method definitions in the body of the class.

Getters and setters can be used to simulate another value:

class ParkEmployee {
  constructor(first, last){
    this.first = first;
    this.last = last;
  }
  sayHi(){
    console.log("Hi, my name is " + this.fullName);
  }
  get fullName(){
    return this.first + " " + this.last;
  }
  set fullName(newVal){
    const parts = newVal.split(" ");
    this.first = parts[0];
    this.last = parts[1];
  }
}

let employee = new ParkEmployee("Ellie","Sattler");

employee.fullName = "John Hammond";

employee.sayHi();
//Logs "Hi, my name is John Hammond"

Method definitions are functions written without the function keyword. They look like the following:

sayHi(){
  console.log("Hi, my name is " + this.fullName);
}

Classes do not allow specifying functions and values on the class prototype using any other syntax available in object literal notation. For example, the following are not allowed:

class ParkEmployee {
  // key: function
  sayHi: function(){
    console.log("Hi, my name is " + this.name);
  }

  // key: value
  name: null
}

Static Methods

The static keywords defines methods directly on the class. For example, the following creates a ParkEmployee.mathematician() method:

class ParkEmployee {
  static mathematician(){
    return new ParkEmployee("Ian");
  }
  constructor(name){
    this.name = name;
  }
  sayHi(){
    console.log("Hi, my name is " + this.name);
  }
}

let goldblum = ParkEmployee.mathematician();
raptorGuy.sayHi();
//Logs "Hi, my name is Ian"

Field Declarations

A few browsers (and Babel) support field declarations. Field declarations let you specify fields (properties) and their initial value up front.

The following declares that ParkEmployee instances will be created with name initialized to undefined and age initialized to 36:

class ParkEmployee {
  name;
  age = 36;
  constructor(name){
    this.name = name;
  }
  sayHi(){
    console.log("Hi, my name is " + this.name);
  }
}

let raptorGuy = new ParkEmployee("Owen");
console.log( raptorGuy.age );
//Logs 36

Sub Classing

Classes (and even constructor functions) can be extended with the extends keyword as follows:

class ParkEmployee {
  constructor( runningSpeed ) {
    this.runningSpeed = runningSpeed;
  }
  run(){
    return "running at " + this.runningSpeed;
  }
}

class Mathematician extends ParkEmployee {
  mustGoFaster(){
    this.runningSpeed = this.runningSpeed * 2;
  }
}

const goldblum = new Mathematician(3);

console.log( goldblum.run() ) //logs "running at 3"

goldblum.mustGoFaster();

console.log( goldblum.run() ) //logs "running at 6"

The keyword super can be used to call functions on a class's (or object's) parent. This is how you call "base" methods.

class ParkEmployee {
  constructor( runningSpeed ) {
    this.runningSpeed = runningSpeed;
  }
  run(){
    return "running at " + this.runningSpeed;
  }
}

class Mathematician extends ParkEmployee {

  // constructor MUST call `super` before accessing `this`
  constructor( name, runningSpeed ) {
    super(runningSpeed);
    this.name = name;
  }
  run(){
    return this.name + " " + super.run();
  }
  mustGoFaster(){
    this.runningSpeed = this.runningSpeed * 2;
  }
}

const goldblum = new Mathematician("ian", 3);

console.log( goldblum.run() ) //logs "ian running at 3"

goldblum.mustGoFaster();

console.log( goldblum.run() ) //logs "ian running at 6"

For a deep dive on the mechanics of class inheritance, checkout JavaScript.info's Class Inheritance guide. It goes into detail about how the [[HomeObject]] internal property is used to enable the super keyword.