Intro to JS OOP
What is object-oriented programming?
Object-oriented programming (OOP) is a way to organize code around objects that bundle data and behavior together. In JavaScript, this usually means using classes to create objects with their own state and methods.
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}!`;
}
}
const user = new User("Alice");
console.log(user.greet()); // "Hello, Alice!"
In this example, the User instance has data (name) and behavior (greet()).
What happens:
class Userdefines the shape and behavior of a user.new User("Alice")creates one user instance.user.greet()runs a method that uses the instance's ownname.
Why this matters
OOP can make code easier to organize when your program has many related things with their own state and behavior: users, orders, game characters, shapes, accounts, tasks, and more.
JavaScript is flexible. You do not need to use OOP for everything. Use it when it makes the model clearer, and use plain objects or functions when those are simpler.
The OOP mental model
Think of an object as a small unit that owns some state and exposes actions for working with that state.
For example, a counter owns a number and exposes methods that change or read that number:
class Counter {
constructor() {
this.value = 0;
}
increment() {
this.value += 1;
return this.value;
}
reset() {
this.value = 0;
}
}
const counter = new Counter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
counter.reset();
console.log(counter.value); // 0
The important idea is not just that the object stores data. The object also controls the operations that belong with that data.
OOP in JavaScript
JavaScript supports OOP with classes:
class Counter {
constructor() {
this.value = 0;
}
increment() {
this.value += 1;
return this.value;
}
}
Classes are modern syntax built on JavaScript's prototype system. You do not need to understand prototypes deeply before using classes, but it helps to know this rule of thumb:
Rule of thumb: each instance gets its own property values, while methods are shared through the class.
Core OOP ideas
Classes and instances
A class is a blueprint. An instance is an object created from that blueprint.
class Car {
constructor(make) {
this.make = make;
}
}
const car1 = new Car("Toyota");
const car2 = new Car("Honda");
console.log(car1.make); // "Toyota"
console.log(car2.make); // "Honda"
car1 and car2 are separate instances.
Properties
Properties store data on an object:
class User {
constructor(name) {
this.name = name;
}
}
const user = new User("Alice");
console.log(user.name); // "Alice"
Methods
Methods are functions attached to objects or classes:
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}!`;
}
}
Methods usually use this to work with the current instance.
this
Inside a method, this refers to the object the method was called on.
class User {
constructor(name) {
this.name = name;
}
rename(newName) {
this.name = newName;
}
}
const user = new User("Alice");
user.rename("Dirk");
console.log(user.name); // "Dirk"
Here, this.name means "the name property on this particular user instance."
Encapsulation
Encapsulation means hiding internal details and exposing a clear interface:
class BankAccount {
#balance = 0;
deposit(amount) {
this.#balance += amount;
}
getBalance() {
return this.#balance;
}
}
Callers can use deposit() and getBalance(), but they cannot directly change #balance.
Inheritance
Inheritance lets one class build on another class:
class Animal {
speak() {
return "Some sound";
}
}
class Dog extends Animal {
speak() {
return "Woof";
}
}
const dog = new Dog();
console.log(dog.speak()); // "Woof"
Inheritance can be useful, but deep inheritance trees become hard to change. Prefer simple designs.
When OOP is a good fit
OOP is usually a good fit when the code has:
- State: Each object needs to remember information.
- Behavior: The object has actions that belong with that information.
- Repeated shape: You need many objects that work the same way.
- Rules: The object should protect its data from invalid changes.
Use a plain object when you only need to group values:
const user = {
name: "Alice",
role: "admin",
};
Use a function when you only need to transform inputs into an output:
function formatUserName(user) {
return `${user.name} (${user.role})`;
}
Use a class when state and behavior naturally belong together:
class TodoItem {
constructor(text) {
this.text = text;
this.completed = false;
}
complete() {
this.completed = true;
}
}
What this section covers
This OOP section covers:
- Classes and instances
- Methods and
this - Encapsulation and private fields
- Inheritance
- Static properties and methods
- Classes vs plain objects
- When to use OOP
Start with Classes and Instances, then move through methods, encapsulation, inheritance, and the final guide on choosing when to use OOP.
What this section does not cover
This section does not go deep into:
- Manual prototype manipulation
- Framework-specific class patterns
- Advanced design patterns
- TypeScript-specific OOP features
The goal is to help you read and write everyday JavaScript classes confidently.
Best practices
- Use OOP when it clarifies the model: Classes work well for stateful entities with behavior.
- Do not force everything into classes: Plain objects and functions are often simpler.
- Keep classes focused: A class should have one clear responsibility.
- Prefer composition over deep inheritance: Combine smaller pieces instead of building tall class trees.
- Use clear method names: Methods should describe actions the object can perform.
Summary
OOP organizes code around objects that combine data and behavior. In JavaScript, classes create instances, properties store state, methods define behavior, and this refers to the current instance. OOP is useful when it makes a problem easier to model, but JavaScript also works well with plain objects, functions, and modules.