Classes

Classes are objects that share the same properties.

A member of a class is called the instance of that class. For example, in the example below, object is an instance of the Object class.

const object = new Object();

Defining a class

JavaScript classes are implemented using prototype-based inheritance. If two objects are members from the same class, they would inherit from the same prototype.

Using a factory function

Not the idiomatic way to define a class.

Using a constructor function

A constructor is a function designed to be invoked with new.

This was the way to declare classes before ES6 introduced the class syntax.

Using the class syntax

The class syntax is introduced in ES6 as a "syntactic sugar" for defining classes. Unlike function declarations, they are "hoisted" to the top of the scope.

At the end of the day, your class definition will still be evaluated as a constructor function just like the above.

The prototype and the constructor property

prototype

Although almost all objects have a prototype, only functions (excluding arrow functions, generator functions, and async functions) have the prototype property. (For example, it makes sense to query <functionName>.prototype.)

The property will<functionName>.prototype be used as the object's prototype when you call new <functionName>().

constructor

The prototype property is an object that contains a single, non-enumerable constructor property that links back to the constructor function.

Since constructor is a property of an object's prototype, then naturally, all object will also inherit the constructor property.

Modifying prototypes

JavaScript's prototype-based inheritance is dynamic: if you add a new method to it, then the classes inheriting from it will also inherit the new method.

Note, however, that this is considered a bad idea because "it will cause confusion and compatibility problems" with future versions of JavaScript (Flanagan).

Extending a class

If class B extends class A:

  • It means that class B will inherit properties of class A. (B can override some or all of the inherited properties, though.)
  • We can say that class B is the subclass of class A.
  • We can say that class A is the superclass of class B.

Extending using constructor functions

In the example below,

  • objects created with new Subclass() will inherit from Subclass.prototype,
  • but Subclass.prototype is an object that inherits from Superclass.prototype (recall Object.create)
  • so, objects created with new Subclass() will inherit from both Subclass.prototype and Superclass.prototype
function Superclass() {...}
Superclass.prototype = {...};

// `Subclass` inherits from `Superclass`
function Subclass() {...}
Subclass.prototype = Object.create(Superclass.prototype);

// If we want to override the constructor
Subclass.prototype.constructor = Subclass;
// If we want to override a method
Subclass.prototype.methodName = function () {...};

Extending using the class syntax

Use the extends keyword.

Inside the subclass constructor, you can use super() to call the superclass' constructor.

class Subclass extends Superclass {
  constructor(...args) {
    // ... do something ...
    super(...args);
    // ... do something ...
  }

  // If you want to implement or or override
  // a method, just write it here.
  methodName() {
    // ... do something ...
  }
}

Static functions

Using the class syntax, you can declare static functions: functions that are called on the class itself, rather than the class instances.

Just put static before the function name inside the class definition.

Instance and static fields

At the time of writing, there is no finalized specification for defining fields, although "standardization is underway" (Flanagan).

The current way:

  • To write instance fields do so in the constructor, using this.<fieldName>
  • To write static fields assign it to the class outside the class body, after the class have been defined
class MyClass {
  constructor() {
    // Write instance fields inside the constructor
    this.instanceField1 = 'someValue';
    this.instanceField2 = 'someValue';
  }
}

// Write static fields outside the class
MyClass.staticField1 = 'anotherValue';
MyClass.staticField2 = 'anotherValue';

References

  • JavaScript: The Definitive Guide, 7th Edition (David Flanagan)Chapter 9. Classes