Design Patterns
Classic design patterns in JavaScript — factory functions, the abstract factory, and the decorator, implemented with closures and ES6 classes.
3 questions
JuniorTheoryVery commonWhat is a factory function, and how does it differ from a constructor with new?
What is a factory function, and how does it differ from a constructor with new?
A factory function is any function that builds and returns a new object, called without new — createUser('Ann') returns the object it assembled. Unlike a new constructor (which creates the object, binds this, and wires its prototype), a factory has no this binding and no automatic prototype link; it controls exactly what it returns and can keep private state in a closure.
Common mistakes
- ✗Thinking a factory must be called with
new— it returns the object itself, sonewis unnecessary - ✗Believing factory-made objects automatically share a prototype like
new-built ones do - ✗Forgetting that a factory can encapsulate private state via closure, which a plain constructor cannot as cleanly
Follow-up questions
- →How would a factory function hide a private counter that the returned object can read but outside code cannot?
- →When is a factory function preferable to an ES6
class?
MiddleCodeOccasionalImplement an abstract factory that produces typed product instances
Implement an abstract factory that produces typed product instances
Make the base create throw so the abstract class cannot be used directly. In CarFactory.create, switch on type: return new Sedan() or new Coupe(), else throw. Callers hold a VehicleFactory reference and call create, so swapping in another factory subclass changes the product family without touching the calling code.
Common mistakes
- ✗Letting the base
createreturn something instead of throwing, so the abstract factory is callable directly - ✗Returning plain object literals instead of real
Sedan/Coupeinstances, losing the prototype chain andinstanceof - ✗Forgetting the
default/else branch, so an unknown type silently returnsundefinedinstead of throwing
Follow-up questions
- →How does depending on
VehicleFactoryrather thannew Sedan()make the calling code easier to extend? - →How would you add a second product family, say
TruckFactory, without changing existing callers?
MiddleCodeOccasionalUse the decorator pattern to wrap a request class without editing it
Use the decorator pattern to wrap a request class without editing it
Define a base Decorator that stores the wrapped object and forwards do to it. Each concrete decorator extends it, adds its behaviour, then calls super.do(...): LoggerDecorator logs the URL, AuthDecorator merges an Authorization header. Because every decorator keeps the same do signature, you compose them — new LoggerDecorator(new AuthDecorator(new GetRequest())) — and the wrapped class is never modified.
Common mistakes
- ✗Editing the wrapped class instead of wrapping it, which defeats the open/closed purpose of the pattern
- ✗Breaking the shared
do(url, options)interface, so decorators can no longer wrap each other - ✗Forgetting to call
super.do(...), so the inner request never actually runs
Follow-up questions
- →How does keeping the same
dosignature on every decorator let you stack them in any order? - →How does the decorator pattern differ from just subclassing
GetRequest?