JavaScript Classes

Blueprints for objects: constructors, methods, inheritance and private fields.

Lesson 52 of 56Advanced13 min read

When you need many objects with the same shape, such as lots of customers, enemies in a game or products in a shop, writing each object by hand gets repetitive. A class is a blueprint: you describe the shape and behaviour once, then create as many objects, called instances, as you need.

Classes are the main tool for a style of programming called object-oriented programming (OOP), where data and the functions that work on it are kept together. You'll meet classes in many libraries and in other languages such as Python and Java, so the ideas here carry over well beyond JavaScript.

Defining and using a class

JavaScript
class Pet {
  constructor(name, species) {
    this.name = name;
    this.species = species;
  }

  describe() {
    return `${this.name} is a ${this.species}`;
  }
}

const pip = new Pet("Pip", "parrot");
pip.describe(); // "Pip is a parrot"
  • Class names use PascalCase, as in Pet or ShoppingCart.
  • constructor runs automatically when you call new Pet(…). Use it to set up the new object.
  • this refers to the instance being created or used.
  • Methods are written without the function keyword, and all instances share them.

Forgetting new is a common mistake. Calling Pet("Pip", "parrot") without it throws an error.

Getters and static methods

  • get total() { … } defines a computed property that you read like a normal property, as cart.total, without brackets.
  • static create() { … } defines a method that belongs to the class itself rather than to instances, so you call it as Pet.create().

Getters are handy for values that depend on other data, such as a basket total that should always reflect the current items.

Inheritance with extends and super

JavaScript
class Dog extends Pet {
  constructor(name) {
    super(name, "dog");   // call the parent's constructor first
  }
  bark() { return "Woof!"; }
}

Dog gets everything Pet has, plus its own extras. A child class can also override a parent's method by defining a method with the same name.

Use inheritance for genuine "is a" relationships: a dog is a pet. Keep inheritance chains short; long chains of classes become hard to follow.

Private fields

Fields whose names start with # can only be used inside the class:

JavaScript
class BankAccount {
  #balance = 0;
  deposit(n) { this.#balance += n; }
  get balance() { return this.#balance; }
}

Outside code can read account.balance through the getter but can't change #balance directly. That protects the object from being put into an invalid state, such as a negative balance set by mistake.

JavaScript Classes Syntax

Class syntax

class Name {
  #secret = 0;              // private field
  constructor(a) { this.a = a; }
  method() { return this.a; }
  get value() { return this.#secret; }
  static helper() { }
}
class Child extends Name {
  constructor(a) { super(a); }
}
const obj = new Name(1);

JavaScript Classes Summary

  • A class is a blueprint for creating many similar objects.
  • constructor sets up each new instance, created with new.
  • Methods are shared by all instances, and this refers to the current instance.
  • extends and super let one class build on another.
  • #private fields can only be accessed inside the class.

JavaScript Classes Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

A simple class

class Timer {
  constructor(label, seconds) {
    this.label = label;
    this.seconds = seconds;
  }

  tick() {
    this.seconds--;
    return this.seconds;
  }

  get display() {
    const m = Math.floor(this.seconds / 60);
    const s = String(this.seconds % 60).padStart(2, "0");
    return `${this.label}: ${m}:${s}`;
  }
}

const tea = new Timer("Tea", 180);
const egg = new Timer("Egg", 361);

tea.tick();
console.log(tea.display);
console.log(egg.display);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 2 to 5The constructor stores each timer's own data.
  2. Lines 7 to 10A method that changes this instance.
  3. Lines 12 to 16A getter, read like a property.
  4. Lines 19 to 20Two separate instances from one blueprint.
Example 2

Inheritance

class Character {
  constructor(name, hp) {
    this.name = name;
    this.hp = hp;
  }
  attack() {
    return `${this.name} attacks for 5 damage`;
  }
}

class Wizard extends Character {
  constructor(name) {
    super(name, 60);
    this.mana = 100;
  }
  attack() {
    this.mana -= 20;
    return `${this.name} casts a fireball for 20 damage (mana ${this.mana})`;
  }
}

const knight = new Character("Sir Bean", 100);
const wiz = new Wizard("Merla");

console.log(knight.attack());
console.log(wiz.attack());
console.log(wiz.hp, wiz instanceof Character);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 11Wizard inherits from Character.
  2. Line 13super(…) runs the parent constructor, which is required before using this.
  3. Lines 16 to 19Override attack with a wizard version.
  4. Line 27Wizards are also Characters.
Example 3

Private fields and static methods

class Cart {
  #items = [];

  add(name, price) {
    this.#items.push({ name, price });
    return this;
  }

  get total() {
    return this.#items.reduce((sum, i) => sum + i.price, 0);
  }

  static fromList(list) {
    const cart = new Cart();
    list.forEach(([n, p]) => cart.add(n, p));
    return cart;
  }
}

const cart = new Cart().add("Socks", 6).add("Hat", 12);
console.log("Total:", cart.total);
console.log(cart.items);

const quick = Cart.fromList([["Pen", 2], ["Pad", 3]]);
console.log("Quick total:", quick.total);
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2A private array. Outside code can't touch it.
  2. Line 6Returning this lets you chain .add().add().
  3. Lines 9 to 11A getter computes the total.
  4. Lines 13 to 17A static "factory" method on the class itself.
  5. Line 22The private field is invisible from outside: undefined.

Common JavaScript Classes Mistakes

Forgetting new

Don't
const p = Pet("Pip", "parrot"); // TypeError: Class constructor cannot be invoked without 'new'
Do
const p = new Pet("Pip", "parrot");

Using this before super

Don't
class Dog extends Pet {
  constructor(name) {
    this.tricks = [];     // ReferenceError
    super(name, "dog");
  }
}
Do
class Dog extends Pet {
  constructor(name) {
    super(name, "dog");
    this.tricks = [];
  }
}

Commas between methods

Don't
class A {
  one() {},
  two() {}
}
Do
class A {
  one() {}
  two() {}
}

Unlike object literals, class bodies don't use commas.

JavaScript Classes in Real Projects

Classes in the real world

Browsers use classes everywhere (every element is an instance of a class like HTMLButtonElement). Game engines model players and enemies with classes, Node.js servers use them for services, and Web Components are built by extending HTMLElement.

JavaScript Classes Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the class.

class Book {
  (title) {
    .title = title;
  }
}
const b =  Book("Dune");
Multiple choicemedium

What does super(name) do inside a child class constructor?

Predict the outputmedium

What does this print?

class Counter {
  #n = 0;
  inc() { this.#n++; return this.#n; }
}
const c = new Counter();
c.inc(); c.inc();
console.log(c.inc(), c.n);
Fix the bugmedium

new Square(4).area should be 16, and Square should extend Shape. Fix it.

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

class Square extends Shape {
  constructor(side) {
    this.side = side;
    super("square");
  }
  get area() {
    return side * side;
  }
}

console.log(new Square(4).area);
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Area of a 4-sided square is 16
  • Square has the name "square"
  • Square is a Shape

JavaScript Classes Quiz

3 questions to check what you learned.

  1. What naming style do classes use?

    • PascalCase
    • camelCase
    • snake_case
    • kebab-case
  2. When does the constructor run?

    • When the class is defined
    • Each time you create an instance with new
    • When a method is called
    • Never automatically
  3. What makes a field private in a class?

    • The private keyword
    • An underscore _balance
    • A # prefix, like #balance
    • Declaring it in the constructor

JavaScript Classes Challenge

Build a Playlist class

Create class Playlist with:

  1. A constructor taking name, starting with an empty songs array
  2. add(title, seconds): pushes { title, seconds } and returns this
  3. A getter duration returning the total seconds
  4. A method summary() returning "Road Trip: 2 songs, 7 min" (minutes rounded down)

const trip = new Playlist("Road Trip");
trip.add("Song A", 200).add("Song B", 250);
console.log(trip.summary());
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Playlist is a class
  • add is chainable
  • duration totals the seconds
  • summary is correct
  • Logs the road trip summary