Classes

What are classes in JavaScript?

Just like constructor functions classes in JavaScript are blueprints (or templates) for creating objects.

Classes in JavaScript are built upon prototype JavaScript functionality and are a type of functions.

Class can be initialized through a class declaration or a class expression. Once a class is declared or expressed it cannot be re-declared or re-expressed.

Class Declarations

A class declaration is signalled using the class keyword.

class Animal {
}

Class declarations - as opposed to function declarations - are not hoisted. Trying to access a class before its declaration results in a RerefenceError.

Class Expressions

Class expressions - just like function expressions - can be unnamed or named.

const Animal = class {
}
Animal // => class {}
Animal.name // => 'Animal'

const Person = class Human {
}
Person // => class Human {}
Human // Uncaught ReferenceError: Human is not defined
Person.name // => 'Human'

Strict Mode

The body of a class is always executed in strict mode - irrespective of whether use strict directive is present or not.

Constructor & Initialization

A class can include one (and only one) constructor method within body. In the constructor method properties of its particular instances can be assigned.

Instances are initialized using the new keyword.

class Animal {
  constructor(species, name) {
    this.species = species
    this.name = name
  }
}

const geraltsHorse = new Animal('horse', 'Roach')
geraltsHorse // => Animal {species: 'horse', name: 'Roach'}

const cirisHorse = new Animal('horse', 'Kelpie')
cirisHorse // => Animal {species: 'horse', name: 'Kelpie'}

Extending Classes

One of the powerful features of classes is their capability of being extended. An extended class (subclass) inherits features of the class it extends (superclass).

class Animal {
  constructor(species, name) {
    this.species = species
    this.name = name
  }

  presentMe() {
    console.log(`I am a ${this.species} and my name is ${this.name}.`)
  }
}

class Horse extends Animal {
}

const napoleonsHorse = new Horse('horse', 'Marengo')
napoleonsHorse.presentMe() // => "I am a horse and my name is Marengo."

Although, the method presentMe() was not defined on the Horse class it is available to instances of the Horse class as the class Horse extends features of the class Animal.

Super

When a subclass defines a property that is already defined on its superclass it overwrites it. However, it is still possible to refer to the superclass property with the super keyword.

If a constructor function is present in a subclass then to use this the keyword super needs to be invoked first.

class Animal {
  constructor(species, name) {
    this.species = species
    this.name = name
  }

  presentMe() {
    console.log(`I am a ${this.species} and my name is ${this.name}.`)
  }  
}

class Horse extends Animal {
  constructor(name) {
    super('horse')
    this.name = name
  }
}

const alexandersHorse = new Horse('Bucephalus')
alexandersHorse // => Horse {species: 'horse', name: 'Bucephalus'}
alexandersHorse.presentMe() // => "I am a horse and my name is Bucephalus."

Single Superclass

In JavaScript there is no multiple inheritance. A class can extend only one class.

Extending Classes with Constructor Functions

It is possible in JavaScript to extend classes with constructor functions. However, it is not possible to extend classes with objects that are not constructor functions.

Instance Methods

Functions defined without a static keyword within a class definition body are assigned as method properties to instances of the class.

class Teacher {
  grade() {
    return 'You get an A!'
  }
}

const profSnape = new Teacher()
profSnape.grade() // => 'You get an A!'

const profHand = new Teacher // Parenthesis are optional with no arguments.
profHand.grade() // => 'You get an A!'

Teacher.grade() // Uncaught TypeError: Teacher.grade is not a function

Static Methods

Functions defined with static keyword within a class definition body become static (aka class) methods that can be invoked directly from the class object but not from its intances.

class Teacher {
  static grade() {
    return 'You get an A!'
  }
}

const profSnape = new Teacher()
profSnape.grade() // Uncaught TypeError: profSnape.grade is not a function

Teacher.grade() // 'You get an A!'

Private Fields

Both instance methods and static methods - as well as all other non-function properties - are public which means that they are accessible from outside of the class definition body. To make them private the sigil # can be used.

class Person {
  #name // A private field needs to be declared first.

  constructor(occupation, name) {
    this.occupation = occupation
    this.#name = name
  }
}

const aKnight = new Person('knight', 'Don Kichot')
aKnight.occupation // 'knight'
aKnight.name // undefined