ECMAScript 2015 Classes

While Javascript’s class syntax is only syntactic sugar over the existing prototype-based inheritance, the support added in ECMAScript 2015 made creating classes in Javascript much more familiar to developers who may be more used to “traditional” class-based languages (e.g. Java, or C#) even if Javascript’s inheritance model itself was not changed.

However, while we can now define class objects and instantiate new instances of those classes using the new ...() syntax just like we can in languages like Java or C#, there are still some limitations that are still important to consider, for example there is no native support for concepts of visibility (i.e. public or private fields - although there is a proposal in the works for private fields).

class MyClass {
  // Empty constructors are not needed.
}

const myClassInstance = new MyClass();
console.log(myClassInstance); // logs "MyClass {}"

Note that a constructor() function is not required.

Class Instance Properties

Class instance properties are properties that are present on each instance of the class - e.g. this.myValue in this example.

class MyClass {
  constructor(myValue) {
    this.myValue = myValue; // Assigns a class instance property.
  }
}
const myClassInstance = new MyClass("hello");
console.log(myClassInstance); // logs "MyClass {myValue: "hello"}"

You do not need to declare the class instance properties, but you can if you want - this could be handy to define default values and you are not initialising in a constructor.

class MyClass {
  myValue;  // Do not need to provide a value!
  notSetInConstructor = "banana";

  constructor(myValue) {
    this.myValue = myValue; // Assigns a class instance property.
  }
}
const myClassInstance = new MyClass();
console.log(myClassInstance); // logs "MyClass {myValue: undefined, notSetInConstructor: "banana"}"

Methods & Static Methods

Simply just add a method as you’d expect - no function prefixes required:

class MyClass {
  myFunction() {
    console.log('Hi');
  }
}
const myClassInstance = new MyClass();
myClassInstance.myFunction(); // logs "Hi"

Static methods obviously do not need an instance - just add the static keyword:

class MyClass {
  static myFunction() {
    console.log('Hi');
  }
}
// No instance required for static members.
MyClass.myFunction(); // logs "Hi"

Getters & Setters

You can use normal object get and set in classes too. This is handy when you need to do some processing before returning a value (e.g. here working out a total amount based on price, quantity and discount), or before setting a value (e.g. here making sure the discount is between 0% and 100%):

class MyClass {
  price = 24.99;
  qty = 5;
  priceDiscount = 0.05;

  get totalPrice() {
    return this.price * this.qty * (1 - this.priceDiscount);
  }

  set discount(amount) {
    if (amount < 0) {
      this.priceDiscount = 0;
    } else if (amount > 1) {
      this.priceDiscount = 1;
    } else {
      this.priceDiscount = amount;
    }
  }
}
const myClassInstance = new MyClass();
myClassInstance.discount = 0.10;
console.log(myClassInstance.totalPrice); // logs 112.455 (10% discount applied)

Inheritance

When subclassing you can extend an existing class - just make sure if you have a constructor in the extending class that you remember to call super.

class Mammal {
  constructor(legs) {
    this.legs = legs;
  }

  howManyLegs() {
    console.log(this.legs);
  }
}

class Cat extends Mammal {
  constructor() {
    super(4); // calls parent class's constructor
  }
}

class Human extends Mammal {
  constructor() {
    super(2); // calls parent class's constructor
  }
}

const cat = new Cat();
const human = new Human();

cat.howManyLegs(); // logs 4
human.howManyLegs(); // logs 2