JavaScript Fundamentals: Classes in JavaScript
Classes are a fundamental building block of object-oriented programming in JavaScript. Introduced in ES6, they provide a cleaner syntax for creating objects and implementing inheritance. This tutorial covers everything you need to know about classes in modern JavaScript.
What Are Classes?
At their core, classes are blueprints for creating objects. They define properties and methods that all instances of the class will have. Think of a class as a recipe — it tells JavaScript how to create something, but you need to actually make the dish (create an instance) to use it.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name}`;
}
}
const alice = new Person("Alice", 30);
console.log(alice.greet());
// Hello, my name is Alice
Class Declaration and Expression
You can declare a class using the class keyword, similar to function declarations. There’s also a class expression form, which is less common but useful in certain situations.
// Class declaration
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
// Class expression
const Square = class {
constructor(side) {
this.side = side;
}
area() {
return this.side * this.side;
}
};
const rect = new Rectangle(10, 5);
console.log(rect.area()); // 50
const sq = new Square(7);
console.log(sq.area()); // 49
Constructor
The constructor is a special method called when you create a new instance with new. It’s where you initialize the object’s properties. A class can only have one constructor.
class BankAccount {
constructor(balance = 0) {
this.balance = balance;
this.transactions = [];
}
deposit(amount) {
if (amount <= 0) {
throw new Error("Deposit amount must be positive");
}
this.balance += amount;
this.transactions.push({ type: "deposit", amount });
return this.balance;
}
withdraw(amount) {
if (amount > this.balance) {
throw new Error("Insufficient funds");
}
this.balance -= amount;
this.transactions.push({ type: "withdraw", amount });
return this.balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
account.withdraw(30);
console.log(account.balance); // 120
Methods
Methods are functions defined inside a class. They can access and modify the object’s properties via this. JavaScript classes support several types of methods.
Instance Methods
These are the most common — they’re available on every instance of the class.
class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
toFahrenheit() {
return (this.celsius * 9/5) + 32;
}
toKelvin() {
return this.celsius + 273.15;
}
}
const temp = new Temperature(25);
console.log(temp.toFahrenheit()); // 77
console.log(temp.toKelvin()); // 298.15
Getters and Setters
Getters and setters let you define computed properties and add validation when setting values.
class User {
constructor(name) {
this._name = name;
this._loginAttempts = 0;
}
get name() {
return this._name;
}
set name(value) {
if (typeof value !== "string" || value.length < 2) {
throw new Error("Name must be a string with at least 2 characters");
}
this._name = value;
}
get isLocked() {
return this._loginAttempts >= 3;
}
recordFailedLogin() {
this._loginAttempts++;
}
}
const user = new User("Bob");
console.log(user.name); // Bob
user.name = "Alice";
console.log(user.name); // Alice
user.recordFailedLogin();
user.recordFailedLogin();
user.recordFailedLogin();
console.log(user.isLocked); // true
Static Methods
Static methods belong to the class itself, not to instances. They’re useful for utility functions related to the class.
class MathUtils {
static average(...numbers) {
if (numbers.length === 0) return 0;
return numbers.reduce((a, b) => a + b, 0) / numbers.length;
}
static clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
}
console.log(MathUtils.average(1, 2, 3, 4, 5)); // 3
console.log(MathUtils.clamp(15, 0, 10)); // 10
console.log(MathUtils.clamp(-5, 0, 10)); // 0
Static Properties
Static properties (added in ES2022) work similarly to static methods — they belong to the class, not instances.
class Counter {
static count = 0;
constructor() {
Counter.count++;
}
static reset() {
Counter.count = 0;
}
}
new Counter();
new Counter();
new Counter();
console.log(Counter.count); // 3
Counter.reset();
console.log(Counter.count); // 0
Inheritance with extends
Inheritance lets you create a new class based on an existing one. The child class inherits all properties and methods from the parent and can add new ones or override existing behavior.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call parent constructor
this.breed = breed;
}
speak() {
return `${this.name} barks`;
}
fetch() {
return `${this.name} fetches the ball`;
}
}
const dog = new Dog("Rex", "German Shepherd");
console.log(dog.speak()); // Rex barks
console.log(dog.fetch()); // Rex fetches the ball
console.log(dog.breed); // German Shepherd
The super keyword calls the parent class’s constructor or methods. It must be called before accessing this in the constructor.
Private Fields
Private fields (prefixed with #) restrict access to class internals. They can’t be accessed or modified from outside the class, enforcing encapsulation.
#balance;
#transactions;
constructor(initialBalance = 0) {
this.#balance = initialBalance;
this.#transactions = [];
}
deposit(amount) {
if (amount <= 0) return false;
this.#balance += amount;
this.#transactions.push({ type: "deposit", amount });
return true;
}
getBalance() {
return this.#balance;
}
getTransactions() {
return [...this.#transactions];
}
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
console.log(account.getTransactions());
// [{ type: "deposit", amount: 50 }]
// These would throw errors:
// console.log(account.#balance);
// account.#balance = 1000000;
Class Expression and instanceof
The instanceof operator checks if an object belongs to a class (or its parent classes).
class Vehicle {
constructor(type) {
this.type = type;
}
}
class Car extends Vehicle {
constructor(brand) {
super("car");
this.brand = brand;
}
}
const myCar = new Car("Toyota");
console.log(myCar instanceof Car); // true
console.log(myCar instanceof Vehicle); // true
console.log(myCar instanceof Object); // true
Quick Reference
Here’s a summary of class features:
| Feature | Syntax | Description |
|---|---|---|
| Declaration | class Name { } | Create a class |
| Constructor | constructor(props) { } | Initialize instances |
| Method | methodName() { } | Instance method |
| Getter | get prop() { } | Computed property |
| Setter | set prop(val) { } | Validated assignment |
| Static | static method() { } | Class-level method |
| Private | #field | Encapsulated field |
| Inheritance | class Child extends Parent | Extend a class |
| Parent call | super.method() | Call parent method |
Summary
Classes in JavaScript provide a clean, object-oriented way to structure your code. Key takeaways:
- Use
classkeyword to declare classes,constructorfor initialization - Methods, getters, setters, and static methods add behavior
- Private fields (
#) enforce encapsulation extendscreates inheritance,superaccesses parent class- Classes are just syntactic sugar over JavaScript’s prototype system
Understanding classes is essential for working with many JavaScript frameworks and writing maintainable, reusable code.