JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
159: The Factory Pattern
A few years ago, I was helping a teammate with a game project. He had a "Combat Manager" file that was nearly 800 lines long, and about half of that was just a massive switch statement used to spawn enemies. Every time he wanted to create an Orc, a Goblin, or a Skeleton, he had to manually instantiate the class, pass in the specific health values, set the attack speed, and assign a loot table. When the lead designer decided that every enemy needed a new "Elemental" property, my teammate spent an entire afternoon hunting down every single new Enemy() call across the codebase to update the constructor arguments. It was a tedious, error-prone slog that could have been avoided entirely.
Abstracting the Creation Logic
This is where the Factory Pattern comes in. At its core, a factory is just a function (or a class with a static method) that handles the complexity of creating objects. Instead of you calling new User() or new Admin() all over your app, you call a factory and tell it what you need. The factory decides which class to instantiate and how to configure it before handing it back to you.
Think of it as a middleman. You don't care how the object is built; you just care that it follows the interface you expect. In JavaScript, this is particularly powerful because we aren't strictly bound by types, but the architectural benefit remains: you decouple the consumption of an object from its creation.
const Orc = {
type: 'Orc',
attack: () => console.log('Swings a heavy axe!')
};
const Goblin = {
type: 'Goblin',
attack: () => console.log('Stabs with a rusty dagger!')
};
class MonsterFactory {
static createMonster(type) {
switch (type) {
case 'orc':
return { ...Orc, health: 100 };
case 'goblin':
return { ...Goblin, health: 50 };
default:
throw new Error('Monster type not recognized');
}
}
}
// Now the rest of the app doesn't need to know about Orc or Goblin specifics
const enemy1 = MonsterFactory.createMonster('orc');
const enemy2 = MonsterFactory.createMonster('goblin');
Decoupling for Future-Proofing
You might be thinking, "Why not just use a simple function?" To be fair, in JavaScript, a factory often is just a function. But the pattern's real value emerges as your project grows. When you use a factory, the "knowledge" of how to build a specific object lives in exactly one place. If you need to change the default health of all Goblins or add a new isElite flag to every spawned monster, you change it in the factory, and every other part of your system automatically receives the update.
I've found this is especially useful when dealing with API responses. If your backend sends a string like "premium_user", your factory can translate that string into a PremiumUser object with all the associated methods and permissions, keeping your UI components clean. You aren't littering your components with if (user.type === 'premium') logic; you're just interacting with an object that the factory guaranteed was built correctly.
📋 Practical Task
The Galactic Shipyard Constructor
You are building a space simulation. Instead of manually creating ships, you need to implement a Shipyard factory that handles the production of different vessel classes. Each ship must have a name, a firepower value, and a shieldStrength value.
Requirements:
- Create a
Shipyardclass with a staticbuildShip(type, name)method. - The factory should handle three types:
- 'scout': Low firepower (10), high shield strength (50).
- 'destroyer': High firepower (100), medium shield strength (40).
- 'carrier': Medium firepower (50), high shield strength (80).
- The returned object should include a method called
statusReport()that logs the ship's name and its combat stats to the console. - If an invalid type is passed, the factory should return a basic 'debris' object with 0 stats.
Test your factory by creating one of each ship type and calling their statusReport() methods.
There are no comments for now.