
你在做一個 UI 編輯器,使用者拖拉出一個按鈕元件,設定了寬度、高度、顏色、圓角、陰影。然後他想要「再做一個差不多的,只是顏色不同」。
你要讓他從頭設定一次嗎?還是直接複製一個、改個顏色就好?
先講結論
Prototype Pattern 的核心就是 clone()。把一個已經設定好的物件複製一份,再微調需要變的部分。比起從頭建立,省去了重複的初始化成本。
classDiagram class Prototype { <<interface>> +clone()* Prototype } class UIComponent { -width : Number -height : Number -color : String +clone() UIComponent +render() String } Prototype <|.. UIComponent UIComponent ..> UIComponent : clone() 產生副本
實戰:UI 元件複製

class UIComponent {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
// 假設這裡有很多昂貴的初始化...
}
clone() {
return Object.assign(
Object.create(Object.getPrototypeOf(this)),
this
);
}
render() {
return `<div style="width:${this.width}px;height:${this.height}px;background:${this.color}"></div>`;
}
}
// 建立原型
const buttonPrototype = new UIComponent(100, 40, 'blue');
// 複製 + 微調
const confirmButton = buttonPrototype.clone();
confirmButton.color = 'green';
const cancelButton = buttonPrototype.clone();
cancelButton.color = 'red';
console.log(confirmButton.render()); // green 按鈕
console.log(cancelButton.render()); // red 按鈕三個按鈕,但只有第一個跑了完整的 constructor。後面兩個都是複製 + 改顏色。
JavaScript 本身就是 Prototype-based
有趣的是,JavaScript 的繼承機制本身就是 prototype-based。每個物件都有一個 __proto__,指向它的原型。你每次用 Object.create() 或 class 的 extends,底層都在用 prototype chain。
所以在 JavaScript 裡,Prototype Pattern 不像在 Java/C++ 那麼「特別」——它就是語言本身的一部分。
小心淺拷貝
Object.assign 做的是淺拷貝。如果物件裡有巢狀物件(array、object),clone 出來的副本會跟原型共用同一個 reference。改了一個、另一個也跟著變。
需要深拷貝的話,用 structuredClone()(現代瀏覽器和 Node 18+ 支援)或 JSON.parse(JSON.stringify(obj))(但不支援 function 和 Date)。
Prototype Pattern 就像影印機——原稿印好了,後面要幾份就印幾份,再用立可白改幾個字就好。只是影印太多次品質會越來越差。