← All concepts
Object-Oriented Programming

ES6 Classes

A class is syntax on top of a constructor function and its prototype, not a new kind of object.

Loading visual…

Definition

The `class` keyword, introduced in ES6, is syntactic sugar over the constructor function and prototype pattern JavaScript already had. Writing `class Dog { constructor(name) { this.name = name; } bark() { return this.name + " barks"; } }` produces the same shape under the hood as a `function Dog(name)` with `this.name = name`, plus a `bark` method assigned to `Dog.prototype`. Every method written inside the class body, other than the constructor, is placed on the prototype automatically, so all instances share one copy instead of getting their own. Calling `new Dog("Rex")` creates a new plain object, sets its internal prototype to `Dog.prototype`, runs the constructor with `this` bound to that new object, and returns it. `class Puppy extends Dog` builds `Puppy.prototype` with `Dog.prototype` as its own prototype, chaining the two, and `super(name)` inside `Puppy`'s constructor calls `Dog`'s constructor first. Classes add conveniences the older pattern does not have for free, like a body that throws if called without `new`, and methods that are non-enumerable by default, but the underlying mechanism is the same prototype chain.

Examples

class Dog {
  constructor(name) {
    this.name = name;
  }
  bark() {
    return this.name + " barks";
  }
}
const rex = new Dog("Rex");
rex.bark(); // "Rex barks"
typeof Dog.prototype.bark; // "function"

bark is defined in the class body but ends up on Dog.prototype, exactly where a hand-written prototype method would live.

class Animal {
  constructor(name) { this.name = name; }
  speak() { return this.name + " makes a sound"; }
}
class Cat extends Animal {
  speak() { return this.name + " meows"; }
}
new Cat("Milo").speak(); // "Milo meows"

extends links Cat.prototype to Animal.prototype, and Cat's own speak on its prototype shadows Animal's version for Cat instances.

class Counter {
  static instances = 0;
  constructor() {
    Counter.instances++;
  }
}
new Counter();
new Counter();
Counter.instances; // 2

static fields and methods live on the class itself, Counter, rather than on Counter.prototype or on individual instances.

Where you see this

Practice this

Further reading