Introduction
When a program needs a hundred accounts, each with the same data and the same operations, writing out a hundred objects by hand is not an option. A class is a template for objects of the same shape. It keeps the data and the code that works on that data together, so that the rules for an account are written once, in one place.
How it works
new makes an object (an instance) and runs the class's constructor to set it up. The visualizer shows each instance in the heap, with its class and its own properties.
Inheritance. class Square extends Rectangle makes a subclass: a Square has everything a Rectangle has, and can add or replace methods. Its constructor must call super(...) (the parent's constructor) before using this. A method with the same name as the parent's overrides it, and super.method() calls the parent's version.
More class features.
| Feature | Example | Meaning |
|---|---|---|
| getter | get area() ... | read like a property: r.area, no brackets |
| static | static count = 0 | belongs to the class itself: Rectangle.count |
| private field | #balance | only code inside the class can read it |
instanceof | s instanceof Rectangle | true if s was made by that class or a subclass |
// A private field, a getter and a static counter.
class Account {
static opened = 0;
#balance = 0;
constructor(owner) {
this.owner = owner;
Account.opened += 1;
}
deposit(amount) {
if (amount <= 0) {
throw new RangeError("Deposit must be positive");
}
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mitu");
acc.deposit(500);
acc.deposit(120);
console.log(acc.owner, acc.balance, Account.opened);Private fields do more than tidy things up. Since nothing outside can change #balance, the deposit method's rule can never be bypassed.
Prototypes underneath. Classes are a clearer way to write what JavaScript does with prototypes. Every object has a hidden link to another object, its prototype. When a property is not on the object itself, JavaScript looks on its prototype, then on that one's prototype, and so on: the prototype chain. Methods live once on the class's prototype, and every instance finds them through the chain, so a thousand rectangles share one area function.
Syntax
class Dog extends Animal {
#age = 0; // private field
constructor(name) {
super(name); // run Animal's constructor
}
speak() {
return `${this.name} says woof`;
}
}
const d = new Dog("Rex");
Example
// A class, two instances, and a subclass.
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
describe() {
return `${this.width} x ${this.height}, area ${this.area()}`;
}
}
class Square extends Rectangle {
constructor(side) {
super(side, side); // the Rectangle constructor
}
describe() {
return "Square " + super.describe();
}
}
const r = new Rectangle(3, 4);
const s = new Square(5);
console.log(r.describe());
console.log(s.describe());
console.log(s instanceof Rectangle, s instanceof Square);Line by line
class Rectangledefines the constructor and two methods. Nothing runs yet.Square extends Rectangle, and its constructor passessidetwice tosuper.Squarereplacesdescribe, and calls the parent's version inside its own.new Rectangle(3, 4)andnew Square(5)make the two objects.s.describe()finds the Square method first. Inside it,this.area()is found on Rectangle.- The last line shows that a Square is also a Rectangle.
Expected result
3 x 4, area 12
Square 5 x 5, area 25
true true
In the real world
Web browsers themselves are built this way: a button element inherits from a general HTML element, which inherits from a general node. Game characters, bank accounts and user interface widgets are common uses for classes. Plain objects and functions are still often simpler, so a class should earn its place.
Common mistakes
- Forgetting
new.Rectangle(2, 3)without it throws a TypeError for a class. - Using
thisin a subclass constructor before callingsuper(). - Forgetting
this.Inside a method,widthalone is a variable, not the property. - Passing a method as a callback.
setTimeout(r.show)loses itsthis. Use an arrow function:() => r.show().
Best practices
- Use a class when many objects share both data and behaviour.
- Keep data private, and offer methods that keep it valid.
- Prefer shallow inheritance. Long chains of parents are hard to follow.
Summary
A class describes a kind of object. new makes an instance and the constructor sets it up. extends and super reuse a parent class. Getters, static members and private fields refine the design. Underneath, methods are shared through the prototype chain.
Quick check
Key takeaways
- new creates an object and runs its constructor.
- A subclass must call super before using this.
- Private fields keep an object's data safe from outside code.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.