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)
161: The Command Pattern
Why can't I just call a function instead of wrapping it in an object?
That's the first thing everyone asks. If you just want to make text bold, why not just call makeBold()? The problem is that a function call is an immediate action. Once it's gone, it's gone. You have no record of it, and you certainly can't "un-call" it.
By turning that request into a Command object, you're essentially turning a verb into a noun. Instead of "doing the thing," you're "creating a thing that knows how to do the thing." This decoupling is huge. It means the piece of code triggering the action (like a button in your UI) doesn't need to know anything about the actual logic of the operation; it just needs to know that the object it's holding has an execute() method.
What does the actual structure look like in JavaScript?
In a language like Java, you'd be dealing with strict interfaces. In JavaScript, we just rely on a consistent shape. Every command object should have a standard method—usually execute()—and often an undo() method if you're tracking history.
Let's imagine we're building a simple text editor. Here is how I'd set up a command to handle changing the text color:
class ChangeColorCommand {
constructor(editor, newColor) {
this.editor = editor;
this.newColor = newColor;
this.oldColor = null; // We'll save this during execution
}
execute() {
// Save the current state so we can revert later
this.oldColor = this.editor.color;
this.editor.color = this.newColor;
console.log(`Color changed to ${this.newColor}`);
}
undo() {
this.editor.color = this.oldColor;
console.log(`Color reverted to ${this.oldColor}`);
}
}
// The "Receiver" - the object actually being manipulated
const myEditor = { color: 'black' };
// The "Client" creates the command
const redCommand = new ChangeColorCommand(myEditor, 'red');
// The "Invoker" (like a button click) executes it
redCommand.execute(); // myEditor.color is now 'red'
How do I use this to actually implement an Undo feature?
This is where the Command pattern really shines. Since each command object stores its own previous state (like oldColor in the example above), you can just push every command you execute onto a stack. When the user hits Ctrl+Z, you pop the last command off the stack and call its undo() method.
I usually implement this with a "Command Manager" or "Invoker" class to keep the history clean. Here's a quick look at how that logic flows:
class CommandManager {
constructor() {
this.history = [];
}
execute(command) {
command.execute();
this.history.push(command);
}
undo() {
if (this.history.length === 0) {
console.log("Nothing to undo!");
return;
}
const command = this.history.pop();
command.undo();
}
}
const manager = new CommandManager();
const redCmd = new ChangeColorCommand(myEditor, 'red');
const blueCmd = new ChangeColorCommand(myEditor, 'blue');
manager.execute(redCmd); // Color: red
manager.execute(blueCmd); // Color: blue
manager.undo(); // Color: red (blueCmd popped and undone)
manager.undo(); // Color: black (redCmd popped and undone)
It's a simple pattern, but it's the backbone of almost every professional software tool that has a history panel or an undo system. You're not saving the entire state of the application every time (which would be a memory nightmare); you're just saving the specific delta needed to reverse a single action.
📋 Practical Task
Exercise: Building a Command-Based Volume Controller
You are building a volume control system for a media player. Instead of just changing a variable, you need to implement it using the Command Pattern so that users can undo their volume changes.
- Create a
VolumeReceiverobject that has avolumeproperty (starting at 50) and a method to log the current volume to the console. - Create a
ChangeVolumeCommandclass. It should take the receiver and anewVolumevalue in the constructor. It must implementexecute()` andundo(). - Create a
RemoteControlclass (the Invoker) that maintains ahistoryarray. It should have anpressButton(command)method to execute and store commands, and anundoPress()method to revert the last action. - Test your implementation: Change the volume to 80, then to 20, then call
undoPress()twice to ensure the volume returns to 50.
There are no comments for now.