Builder constructs a complex object step by step, useful when an object has many optional configuration options and a constructor with a dozen parameters would be unreadable and error-prone.
// Without Builder — unreadable, easy to mix up parameter order
burger = new Burger(true, false, true, false, true, "large", true)
// With Builder — self-documenting, chainable, order-independent
class BurgerBuilder {
function addCheese() { this.hasCheese = true; return this }
function addBacon() { this.hasBacon = true; return this }
function setSize(size) { this.size = size; return this }
function build() { return new Burger(this) }
}
burger = new BurgerBuilder()
.addCheese()
.addBacon()
.setSize("large")
.build()
Each builder method returns this, enabling the method chaining (or 'fluent interface') style shown above. This pattern is extremely common in real-world libraries — SQL query builders, HTTP request builders, and UI layout builders all typically follow this shape.
Prototype creates new objects by copying (cloning) an existing object, rather than building one from scratch — useful when object creation is expensive, or when you want a new object that's mostly identical to an existing one with a few small changes.
class Character {
function __construct(name, level, inventory) {
this.name = name
this.level = level
this.inventory = inventory // a large, complex nested structure
}
function clone() {
return new Character(this.name, this.level, deepCopy(this.inventory))
}
}
template = new Character("Base Warrior", 1, defaultInventory)
player1 = template.clone()
player1.name = "Alice"
player2 = template.clone()
player2.name = "Bob"
// Both start from the same expensive-to-build base configuration, without re-running full setup
A proper clone must be a deep copy for any nested objects/arrays — a shallow copy that just copies references would leave player1 and player2 accidentally sharing the same underlying inventory object, causing one player's changes to silently affect the other.