Prototype Design Pattern
I was generating test data for a vehicle inventory system. Each test needed slightly different vehicle objects — different models, different years — but 8...
23 Mar 2024

I was generating test data for a vehicle inventory system. Each test needed slightly different vehicle objects — different models, different years — but 80% of the properties were the same. Building each one from scratch was tedious and error-prone.
The Prototype pattern lets you create new objects by cloning an existing one. Instead of constructing from scratch, you copy a prototype and modify what's different. The original stays untouched.
Think of it like using a template in a word processor. You start with a pre-filled document and just change the parts that are specific to this use.
const vehiclePrototype = {
type: "car",
make: "Toyota",
model: "Camry",
year: 2022,
clone() {
return Object.create(this);
}
};
const vehicle1 = vehiclePrototype.clone();
vehicle1.model = "Corolla";
const vehicle2 = vehiclePrototype.clone();
vehicle2.year = 2023;
console.log(vehicle1.model); // Corolla
console.log(vehicle1.make); // Toyota (inherited from prototype)
console.log(vehicle2.year); // 2023
console.log(vehicle2.model); // Camry (inherited from prototype)
clone() creates a new object with the prototype as its parent. Properties you override are set on the clone. Properties you don't override are inherited from the prototype through JavaScript's prototype chain.
Important: Shallow vs Deep Copy
Object.create() sets up prototype linkage — it's not a true copy. For flat objects, that's fine. For objects with nested properties (arrays, objects), changes to nested values on the clone will affect the prototype. Use structuredClone() or a deep clone utility when your prototype has nested data.
const configPrototype = {
name: "default",
settings: { theme: "light", language: "en" },
clone() {
return structuredClone(this);
}
};
const myConfig = configPrototype.clone();
myConfig.settings.theme = "dark";
console.log(configPrototype.settings.theme); // "light" (unaffected)
The benefit: Fast object creation. No need for complex constructors. Great for creating many similar objects with minor variations. Reduces boilerplate in test data generation and configuration management.
The cost: Shallow cloning pitfalls. Developers forget about shared references and introduce subtle bugs. The prototype chain can also confuse developers who expect hasOwnProperty to return true for inherited values. And if your object construction has important side effects (validation, registration), cloning bypasses those.
I use the Prototype pattern for test fixtures, default configuration objects, and scenarios where object creation is expensive (like cloning a complex parsed DOM structure). For simple objects, just use object spread { ...defaults, ...overrides } — it's more explicit and easier to understand.