Turn a request into a standalone object, so it can be queued, logged, or undone instead of executing immediately.
A text editor's toolbar button calling `document.insertText(x)` directly has no way to undo that specific action later, and no way to queue several actions to run in sequence or replay them.
Each command implements `execute()` and `undo()`. An invoker (like an undo stack) holds a history of executed commands and can call `undo()` on the most recent one without knowing what kind of action it was.
`undo()` reverses exactly what `execute()` did, so the invoker can pop the stack without knowing what kind of edit it was.
class Document { text = ""; }
class InsertTextCommand {
constructor(doc, text) { this.doc = doc; this.text = text; }
execute() { this.doc.text += this.text; }
undo() { this.doc.text = this.doc.text.slice(0, -this.text.length); }
}
class CommandStack {
#history = [];
run(command) { command.execute(); this.#history.push(command); }
undoLast() { this.#history.pop()?.undo(); }
}
const doc = new Document();
const stack = new CommandStack();
stack.run(new InsertTextCommand(doc, "Hello"));
stack.run(new InsertTextCommand(doc, ", world"));
console.log(doc.text); // "Hello, world"
stack.undoLast();
console.log(doc.text); // "Hello"