❓ A Question That Confused Me
As we continue learning Object-Oriented Programming, I want to pause for a moment and discuss something that often comes up for JavaScript developers.
When we hear about OOP, we usually hear about classes.
class User {
constructor(name) {
this.name = name;
}
}
We've discussed that classes are used to create objects.
Fair enough.
But then we look at JavaScript codebases and see something like this:
function createUser(name) {
return {
name
};
}
No class.
No constructor.
No new keyword.
And yet, we're still creating objects.
This raises a very reasonable question:
What is this called? And if these kinds of functions can create objects, why do classes exist?
To answer that, let's first understand the problem developers were trying to solve.
The Simplest Possible Approach
Suppose we're building an application and need user objects.
Our first instinct might be:
const user1 = {
name: "Ashay",
email: "ashay@gmail.com"
};
const user2 = {
name: "Rahul",
email: "rahul@gmail.com"
};
Looks fine.
Until we realize that every user should also be able to update their email.
const user1 = {
name: "Ashay",
email: "ashay@gmail.com",
updateEmail(newEmail) {
this.email = newEmail;
}
};
Then another user.
And another.
And another.
Soon, we're repeating the same structure everywhere.
The First Problem: Repetition
The problem isn't creating one object.
The problem is creating hundreds of similar objects.
We don't want to keep rewriting:
{
name,
email,
updateEmail() {
...
}
}
over and over again.
We need a way to create objects consistently.
This is where factory functions come in.
Factory Functions
A factory function is simply a function whose job is to create and return objects.
function createUser(name, email) {
return {
name,
email,
updateEmail(newEmail) {
this.email = newEmail;
}
};
}
Now creating users becomes easy.
const user1 = createUser("Ashay", "ashay@gmail.com");
const user2 = createUser("Rahul", "rahul@gmail.com");
Instead of manually constructing objects every time, we have a single place responsible for creating them.
Why Developers Loved Factory Functions
At this point many developers thought:
This is great. Why do I need anything more?
And honestly, for many situations, you don't.
Factory functions provide several benefits naturally.
Object creation becomes consistent.
Every user now has the same structure.
No accidental missing fields.
No forgotten methods.
The factory handles everything.
We Can Hide Internal Details
Imagine building a counter.
We don't want other parts of the app directly changing the count.
Without a factory:
const counter = {
count: 0
};
Anyone can do:
counter.count = 1000;
Maybe that's not what we want.
With a factory:
function createCounter() {
let count = 0;
return {
increment() {
count++;
},
getValue() {
return count;
}
};
}
Now the internal state is protected.
counter.count = 1000;
doesn't affect the actual value.
This was one of the biggest strengths of factory functions.
So Why Were Classes Introduced?
At this point factory functions seem pretty good.
They reduce repetition.
They create objects.
They can even hide internal state.
So why introduce classes?
Because developers encountered a different problem.
Not object creation.
Object organization.
Imagine a large e-commerce system.
You have:
- Products
- Orders
- Customers
- Payments
- Discounts
- Shipments
Suddenly, there are dozens of related entities interacting with each other.
Developers wanted a standardized way to describe:
- What a Product is
- What an Order is
- What behaviors they have
- How they relate to one another
Classes provided a structured blueprint for doing this.
The Important Realization
The interesting thing is that classes and factory functions are not enemies.
They're trying to solve similar problems from different angles.
Factory Functions answer:
How can I create objects consistently?
Classes answer:
How can I model and organize complex object-oriented systems?
Both create objects.
Both can be useful.
Both have trade-offs.
Understanding those trade-offs is far more important than blindly choosing one over the other.
What Should You Use?
For small and medium-sized object creation needs, factory functions are often wonderfully simple.
For larger systems with complex relationships, many teams prefer classes because they provide a more familiar structure.
The right choice depends on the problem you're solving.
And that's a recurring theme you'll see throughout this series:
Good software design is rarely about choosing the "best" solution.
It's about understanding the problem and choosing the most appropriate trade-off.
⏭️ What's Next?
Now that we've explored different ways of creating objects, we can return to Object-Oriented Programming itself.
In the next article, we'll start exploring the first major OOP principle: Encapsulation.
We'll look at the problems that arise when an object's internal state can be modified freely and how Encapsulation attempts to solve them.

Top comments (0)