Classes
A class is a template for creating objects with the same properties and methods.
Classes appeared in ES6 and are syntax over prototypes: methods are stored
in ClassName.prototype, and extends links the prototypes of two classes. See
Prototypes.
Unlike constructor functions, classes:
- can be called only with
new; - are not available before the declaration (temporal dead zone);
- always run in strict mode;
- have non-enumerable methods.
Details
Basic Syntax
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(
`Hello, my name is ${this.name} and I am ${this.age} years old.`
);
}
}
const person1 = new Person('John', 30);
person1.greet(); // Hello, my name is John and I am 30 years old.
Fields, Getters and Setters
- Public fields (
count = 0;) are own properties created for each instance before the constructor body runs. A field holding an arrow function keepsthiswhen the method is passed as a callback. get/setdefine accessor properties on the prototype:get fullName() {}is read asuser.fullName.
Inheritance
The extends keyword creates a subclass. A subclass constructor must call
super() before using this. super.speak() calls the parent's method. A
subclass without a constructor gets constructor(...args) { super(...args); }
by default.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
console.log(`${this.name} barks.`);
}
}
const dog1 = new Dog('Rex', 'German Shepherd');
dog1.speak(); // Rex barks.
Private Members
ECMAScript 2022 introduced support for private fields and methods using the #
prefix. Private fields and methods are only accessible within the class where
they are defined.
class Car {
#engineStarted = false;
startEngine() {
this.#engineStarted = true;
console.log('Engine started');
}
#checkEngine() {
return this.#engineStarted;
}
status() {
if (this.#checkEngine()) {
console.log('The engine is running');
} else {
console.log('The engine is off');
}
}
}
const car1 = new Car();
car1.startEngine(); // Engine started
car1.status(); // The engine is running
JavaScript has no protected members (accessible in the class and its
subclasses only). A leading underscore (_name) is just a naming convention:
the property stays public.
instanceof
It checks whether an object is an instance of a specific class or constructor function.
// assuming this code is executed after the code given above
console.log(dog1 instanceof Animal); // true
console.log(dog1 instanceof Dog); // true
console.log(dog1 instanceof Car); // false
Static Members
Static methods and fields are defined on the class itself, not on instances.
They are used for utility functions and factories. A static {} block runs once
when the class is created.
class MathUtilities {
static add(a, b) {
return a + b;
}
}
console.log(MathUtilities.add(5, 3)); // 8
Follow-up Questions
- Why must
super()be called beforethisin a subclass constructor? The object is created by the base constructor; untilsuper()returns there is nothis(ReferenceError). - How do you keep
thisin a class method used as a callback? Bind it in the constructor (this.handle = this.handle.bind(this)) or make it an arrow function field (handle = () => {}). Seethis. - Can a class extend several classes? No; use composition or mixins. See OOP Principles.
Common Mistakes
- "Classes are just syntax sugar, nothing else." They also require
new, are in the TDZ, run in strict mode and have non-enumerable methods. - Passing
obj.methodas a callback and losingthis(React class components,addEventListener). - "
_nameis private." Only#nameis enforced; the underscore is a convention.