Guide to JavaScript Classes

1. Overview

JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. It does not offer any new way of object creation or prototype inheritance and does not bring any new models of object orientation or inheritance in JavaScript. You could say that a class is a special function to create objects.

For the best learning experience, I highly recommended that you open a console (which, in Chrome and Firefox, can be done by pressing Ctrl+Shift+I), navigate to the "console" tab, copy-and-paste each JavaScript code example from this guide, and run it by pressing the Enter/Return key.
For example, let's demonstrates the javascript classes are nothing but just a new way of writing the constructor functions by utilizing the power of prototype, let's see an example for this:
class Vehicle {
    constructor(make, model, color) {
        this.make = make;
        this.model = model;
        this.color = color;
    }

    getName() {
        return this.make + " " + this.model;
    }
}
And in order to create a new instance of class Vehicle, we do this:
let car = new Vehicle("Toyota", "Corolla", "Black");
You can test the above example by running in browser console:

2. Define JavaScript Classes

2.1 Class declarations

One way to define a class is by using a class declaration. To declare a class, we use the class keyword with the name of the class ("Employee" here).
class Employee {
    constructor(firstName, lastName, emailId, age){
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailId = emailId;
        this.age = age;
    }

    getFullName(){
        return this.firstName + " " + this.lastName;
    }

    getFirstName(){
        return this.firstName;
    }
}

2.2 Hoisting

You first need to declare your class and then access it, otherwise, code like the following will throw a ReferenceError:
const p = new Rectangle(); // ReferenceError

class Rectangle {}

2.3 Class expressions

A class expression is another way to define a class. Class expressions can be named or unnamed. The name given to a named class expression is local to the class's body. (it can be retrieved through the classes (not an instance's) name property, though).
// unnamed
let Employee = class {
    constructor(firstName, lastName, emailId, age){
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailId = emailId;
        this.age = age;
    }

    getFullName(){
        return this.firstName + " " + this.lastName;
    }

    getFirstName(){
        return this.firstName;
    }
}

console.log(Employee.name);
// output: "Employee"

// named
 let Employee = class Employee1{
    constructor(firstName, lastName, emailId, age){
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailId = emailId;
        this.age = age;
    }

    getFullName(){
        return this.firstName + " " + this.lastName;
    }

    getFirstName(){
        return this.firstName;
    }
}

console.log(Employee.name);
// output : "Employee1"

3. Class body and method definitions

3.1 Strict mode

The code inside a class is always in strict mode, this helps to write error-free code, by throwing errors, on mis typings, or syntactical errors done while writing code, or even removing some code by mistake, which is referenced from somewhere else.

3.2 Constructor

The constructor method is a special method for creating and initializing an object created with a class. There can only be one special method with the name "constructor" in a class. A SyntaxError will be thrown if the class contains more than one occurrence of a constructor method.
class Employee {
    constructor(firstName, lastName, emailId, age){
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailId = emailId;
        this.age = age;
    }
}
A constructor can use the super keyword to call the constructor of the superclass.

3.3 Prototype methods

class Rectangle {
     constructor(height, width) {
          this.height = height;
          this.width = width;
     }
   // Getter
     get area() {
         return this.calcArea();
     }
     // Method
     calcArea() {
          return this.height * this.width;
     }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100

3.4 Static methods

The static keyword defines a static method for a class. Static methods are called without instantiating their class and cannot be called through a class instance. Static methods are often used to create utility functions for an application.
class Point {
     constructor(x, y) {
          this.x = x;
          this.y = y;
     }

     static distance(a, b) {
          const dx = a.x - b.x;
          const dy = a.y - b.y;

          return Math.hypot(dx, dy);
     }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2)); 
Output:
7.0710678118654755

3.5 Field declarations

Public field declarations

Below example demonstrates the declaring public fields in Rectangle class:
class Rectangle {
     height = 0;
     width;
     constructor(height, width) {    
          this.height = height;
          this.width = width;
     }
}
By declaring fields up-front, class definitions become more self-documenting, and the fields are always present. As seen above, the fields can be declared with or without a default value.

Private field declarations

Using private fields, the definition can be defined as below.
class Rectangle {
     #height = 0;
     #width;
     constructor(height, width) {    
          this.#height = height;
          this.#width = width;
     }
}

3.6 Getters/Setters

The class can also have getter/setters to get the property value and or to set the property values. Something like below.
class Vehicle {
    constructor(model) {
        this.model = model;
    }
    
    get model() {
        return this._model;
    }

    set model(value) {
        this._model = value;
    }
}
Under the hood, getters/setters are defined on the class prototype.

3.7 Subclassing

Subclassing is a way you can implement inheritance in Javascript classes, keyword extends is used to create a child class of a class.
class Animal { 
     constructor(name) {
           this.name = name;
     }
  
     speak() {
          console.log(this.name + ' makes a noise.');
     }
}

class Dog extends Animal {
     constructor(name) {
          super(name); // call the super class constructor and pass in the name parameter
     }

     speak() {
          console.log(this.name + ' barks.');
     }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
If there is a constructor present in the subclass, it needs to first call super() before using "this".
One may also extend traditional function-based "classes":
function Animal (name) {
     this.name = name;  
}

Animal.prototype.speak = function () {
     console.log(this.name + ' makes a noise.');
}

class Dog extends Animal {
    speak() {
       console.log(this.name + ' barks.');
    }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
Note that classes cannot extend regular (non-constructible) objects. If you want to inherit from a regular object, you can instead use Object.setPrototypeOf():
const Animal = {
     speak() {
          console.log(this.name + ' makes a noise.');
     }
};

class Dog {
     constructor(name) {
          this.name = name;
     }
}

// If you do not do this you will get a TypeError when you invoke speak
Object.setPrototypeOf(Dog.prototype, Animal);

let d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.

4. References



Comments