DEV Community

Cover image for JavaScript Classes (With Examples)
Richard Rembert
Richard Rembert

Posted on

JavaScript Classes (With Examples)

JavaScript classes were introduced with ECMAScript 2015, they’re often described as syntactical sugar over JavaScript’s existing structure of prototypical inheritance. So while classes do not introduce a new inheritance model to JavaScript — they do provide syntactical simplicity. This simplicity can help us produce less error-prone & more readable code.

Classes are just like Functions

Classes are very similar to functions. Much like functions that have both function expressions and function declarations, classes have two components: class expressions and class declarations.

Class Declarations

Let's take a look at how we can define a class using a class declaration. We use the class keyword followed the name of the class:

class Image {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
Enter fullscreen mode Exit fullscreen mode

Hoisting

One important difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. You first need to declare your class and then access it, otherwise, code like the following will throw a ReferenceError:

const p = new Image(); // ReferenceError

class Image{}
Enter fullscreen mode Exit fullscreen mode

Class Expressions

A class expression is the other way to define a class. Class expressions can be named or unnamed. Note that the name given to a named class expression is local to the class’s body. (So it’s retrievable through the classes name property):

// An unnamed class expression
let Image = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Image.name);
// output: "Image"

// A named class expression
let MyImage = class Image {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(MyImage.name);
// output: "Image"
Enter fullscreen mode Exit fullscreen mode

Note: Class expressions are subject to the same hoisting restrictions as described previously in the Class declarations section.

Constructors

The constructor method is a special method within JavaScript that we use to create and initialize an object created with a class. We can only use one method with the name "constructor" within a class.

Our constructor can use the super keyword to call the constructor of the super class (more on this later in the article!).

Instance Properties

Instance properties must be defined inside of our class methods:

class Image {
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}
Enter fullscreen mode Exit fullscreen mode

If we wish to use static class-side properties and prototype data properties, these must be defined outside of the classes body declaration:

Image.staticWidth = 50;
Image.prototype.prototypeWidth = 55;
Enter fullscreen mode Exit fullscreen mode

Field Declarations

Whilst the syntax is still considered experimental (it’s not yet adopted by many browsers), public and private field declarations are also worth knowing about — as often you’ll be developing with a Babel which will transpire the syntax for you.

Public Field Declarations

Let’s revisit our example with the JavaScript field declaration syntax:

class Image {
  height = 0;
  width;
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}
Enter fullscreen mode Exit fullscreen mode

The difference is our fields have been declared up-front. So our class definitions become more self-documenting, and the fields are always present.

Note: the fields can be declared with or without a default value!

Private Field Declarations

When we use private fields, the definition can be refined like so:

class Image {
  #height = 0;
  #width;
  constructor(height, width) {    
    this.#height = height;
    this.#width = width;
  }
}
Enter fullscreen mode Exit fullscreen mode

Private fields (declared with a #) cannot be referenced outside of the class, only within the class body. This ensures that your classes’ users can’t depend on internals, which may change with version changes.

Note: Private fields cannot be created later through assignment. They can only be declared up-front in a field declaration.

Child Classes Using 'extends'

We can use the extends keyword with either class declarations or class expressions to create a class as a child of another class.

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

  sound() {
    console.log(`${this.name} makes a sound.`);
  }
}
class Car extends Vehicle{
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }
  sound() {
    console.log(`The ${this.name} tooted its horn!`);
  }
}
let c = new Car('Volkswagen');
c.sound(); // The Volkswagen tooted its horn!
Enter fullscreen mode Exit fullscreen mode

If there is a constructor present in the subclass, it needs to first call super() before using “this”.

Function-based “classes” may also be extended:

function Vehicle (name) {
  this.name = name;  
}
Vehicle.prototype.sound = function () {
  console.log(`${this.name} makes a sound.`);
}
class Car extends Vehicle{
  speak() {
    console.log(`The ${this.name} tooted its horn!`);
  }
}
let c = new Car('Volkswagen');
c.sound(); // The Volkswagen tooted its horn!
Enter fullscreen mode Exit fullscreen mode

Note: classes cannot extend regular objects! If you want to inherit from an object, use Object.setPrototypeOf():

const Vehicle = {
  sound() {
    console.log(`${this.name} makes a sound.`);
  }
};

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

let c = new Car('Volkswagen');
c.sound(); // Volkswagen makes a sound.
Enter fullscreen mode Exit fullscreen mode

Species

If you want to return Array objects from an array class MyArray. You can do so with the “species” pattern, which lets you override the default constructors.

If using methods such as map() it’ll return the default constructor. Then you’ll want these methods to return a parent Array object, instead of the MyArray object. Symbol.specieslets you do this, like so:

class MyArray extends Array {
  // Overwrite species to the parent Array constructor
  static get [Symbol.species]() { return Array; }
}

let a = new MyArray(1,2,3);
let mapped = a.map(x => x * x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true
Enter fullscreen mode Exit fullscreen mode

The ‘Super’ Keyword

The super keyword is used to call corresponding methods of super class. This is one advantage over prototype-based inheritance. Let’s see an example:

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

  sound() {
    console.log(`${this.name} makes a sound.`);
  }
}

class Beetle extends Volkswagen {
  sound() {
    super.sound();
    console.log(`${this.name} toots it's horn.`);
  }
}

let b = new Beetle('Herbie');
b.sound(); 

// Herbie makes a sound.
// Herbie toots it's horn.
Enter fullscreen mode Exit fullscreen mode

Mix-ins

Mix-ins are templates for classes. An ECMAScript class can only have a single superclass, so multiple inheritance from tooling classes, for example, isn’t possible. The functionality must be provided by the superclass.

A function with a superclass as input and a subclass extending that superclass as output can be used to implement mix-ins in ECMAScript:

let calculatorMixin = Base => class extends Base {
  calc() { }
};

let randomizerMixin = Base => class extends Base {
  randomize() { }
};
Enter fullscreen mode Exit fullscreen mode

A class that uses these mix-ins can then be written like this:

class First { }
class Second extends calculatorMixin(randomizerMixin(First)) { ...
Enter fullscreen mode Exit fullscreen mode

We’ve taken a deep dive into JavaScript classes including class declarations, class expressions, constructors, instance properties, field declarations, extends, species, super and mix-ins.

Conclusion

If you liked this blog post, follow me on Twitter where I post daily about Tech related things!
Buy Me A Coffee If you enjoyed this article & would like to leave a tip — click here

🌎 Let's Connect

Top comments (0)