Classes, Constructors, and Static Methods
Objectives
By the end of this chapter, you should be able to:
- Define a class with
classand give it aconstructor() - Add instance methods that every object made from the class can call
- Add static methods that belong to the class itself, not to any one instance
- Explain what a
classis actually doing underneath, using what you saw in lesson 1
💡 Why this matters: Almost all real-world JavaScript code you’ll read, including popular libraries, defines its objects with
class. It’s the standard way to describe “here’s a blueprint for making objects that all behave the same way.”
Defining a Class
class Circle {
constructor(radius) {
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
const c1 = new Circle(2);
console.log(c1.area());
// 12.566370614359172
constructor() runs automatically when you write new Circle(2). Whatever you assign to this inside it becomes a property on the new object, here this.radius = radius. area() is an instance method: every Circle object can call it.
This Is the Same Prototype Pattern from Lesson 1
class isn’t a new kind of object. It’s cleaner syntax for the constructor-function-plus-.prototype pattern from the last lesson. Proof:
console.log(typeof Circle.prototype.area);
// function
console.log(Object.getPrototypeOf(c1) === Circle.prototype);
// true
area was defined inside the class body, but JavaScript placed it on Circle.prototype, exactly where Dog.prototype.bark lived in lesson 1. Every Circle instance shares that one area function through the same prototype link you saw before. class just hides the .prototype wiring so you don’t have to write it by hand.
const c2 = new Circle(3);
console.log(c1.area === c2.area);
// true
Static Methods
An instance method belongs to each object made from the class. A static method belongs to the class itself, and you call it directly on the class, never on an instance. Static methods are useful for utility or “factory” functions that relate to the class but don’t need a specific instance to run.
class Circle {
constructor(radius) {
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
static fromDiameter(diameter) {
return new Circle(diameter / 2);
}
}
const c3 = Circle.fromDiameter(10);
console.log(c3.radius);
// 5
console.log(c3.area());
// 78.53981633974483
Circle.fromDiameter(10) is called on the class Circle, not on any particular circle, because at that point no circle exists yet, it’s the thing building one. Trying to call it on an instance fails, because static methods never end up on the instance or on Circle.prototype:
console.log(c3.fromDiameter);
// undefined
c3.fromDiameter(10);
// TypeError: c3.fromDiameter is not a function
Try It
- Write a class
Rectanglewith aconstructor(width, height)and an instance methodarea(). Create one and log its area. - Add a static method
Rectangle.square(side)that returns a newRectanglewith equal width and height. Call it and log the resulting area. - Confirm two different
Rectangleinstances share the sameareafunction with===, the same wayCircledid in this lesson. - Try calling your static method on an instance instead of the class (like
myRectangle.square(4)) and confirm you get aTypeError.
Recap
classdefines a blueprint;constructor()runs when you create a new instance withnew.- Instance methods live on
ClassName.prototypeand are shared by every instance, exactly like the prototype pattern from lesson 1. - Static methods belong to the class itself, called as
ClassName.methodName(), and aren’t reachable from an instance. classis syntax on top of prototypes, not a different mechanism.
Next lesson: encapsulation and private fields, for keeping an object’s internal details separate from what it exposes.