Classes in JavaScript

Aug 27, 2019

In object-oriented programming, a class is a template for creating objects. JavaScript's class keyword is how you declare a new class in JavaScript.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

const obj = new Rectangle(3, 5);
obj.height; // 3
obj.width; // 5

// The `instanceof` keyword is how you test whether an object was created
// from a certain class.
obj instanceof Rectangle; // true
({}) instanceof Rectangle; // false

Methods

A method is a function defined in your class that JavaScript adds to every instance of that class. For example, suppose you wanted to compute the area of a Rectangle. You can define an area() method as shown below.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  // To define a method named `methodName`, you put `methodName() {}` in
  // the class declaration.
  area() {
    return this.width * this.height;
  }
}

const obj = new Rectangle(3, 5);
obj.area(); // 15

In a method, the this keyword refers to the class instance the method is attached to. In the above example, this refers to obj.

Statics

A static is a a function that is defined on the class itself. In JavaScript, a class is just another variable, so you can call static functions on a class.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  // To define a static named `functionName`, you put
  // `static functionName() {}` in the class declaration.
  static createSquare(length) {
    return new Rectangle(length, length);
  }
}

const obj = Rectangle.createSquare(5);
obj.height; // 5
obj.width; // 5

Getters/Setters

An alternative way to define the area of a Rectangle is using getters. Using a getter, you can make area a dynamically computed property of a Rectangle, rather than a method.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  // To define a getter named `getterName`, put `get getterName() {}`
  // in the class definition. Getters are functions!
  get area() {
    return this.height * this.width;
  }
}

const obj = new Rectangle(3, 5);
obj.area; // 15

You can also define a custom setter, which gets called when you set a property. For example, suppose you want to be absolutely certain that height and width are numbers. You can define a custom setter that throws an exception whenever someone tries the set height to a non-numeric value.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  get height() {
    return this._height;
  }

  set height(v) {
    assert.ok(typeof v === 'number', 'Height must be a number');
    return v;
  }

  get width() {
    return this._width;
  }

  set width(v) {
    assert.ok(typeof v === 'number', 'Width must be a number');
    return v;
  }
}

const obj = new Rectangle(3, 5);
// Throws 'AssertionError: Height must be a number'
obj.height = 'Not a number';

Inheritance

When a class extends another class, that means the subclass has all the same statics, methods, getters, and setters as the parent class by default. But then the subclass can define additional statics, methods, getters, and setters. The subclass can also override the base class's statics, methods, getters, and setters.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  area() {
    return this.width * this.height;
  }
}

class Square extends Rectangle {
  constructor(length) {
    // `super` refers to the base class' constructor
    super(length, length);
  }

  // The radius of the inscribed circle
  // See: see http://mathworld.wolfram.com/Square.html
  inradius() {
    return this.height / 2;
  }
}

const obj = new Square(5);

obj.area(); // 25, from `Rectangle` base class
obj.inradius(); // 2.5, from `Square` class

obj instanceof Square; // true
obj instanceof Rectangle; // true

Inheritance is Still Prototype-Based

The extends keyword still uses prototype-based inheritance under the hood. That means you can use prototype-based patterns in combination with ES6 classes.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Rectangle.prototype.area = function area() {
  return this.width * this.height;
};

const obj = new Rectangle(3, 5);

obj.area(); // 15

Did you find this tutorial useful? Say thanks by starring our repo on GitHub!

More Fundamentals Tutorials