JavaScript 的 singleton 可以用 class 或 ES module 兩種方式實作,兩者設計理念有明顯差別。123

核心比較

特色Class SingletonES Module Singleton
基本原理透過 class static 欄位紀錄唯一 instance,只能透過 getter 取得利用 ES module cache,每次 import 都是同一份物件
封裝能力可用 # 私有欄位或 closure 隱藏細節,可自定 instance 行為module 變數為私有,只有 export 部分可被外部存取
多份 instance可視需求設計允許參數化 support 多 singleton(如多 db),也可全域 unique全檔案全域唯一,通常無法有多個,不利參數化
TypeScript 支援完全 type-safe,適合複雜 OOP case純物件、function 較平面,少 OOP 結構
用法const s = Singleton.getInstance()import singleton from './mySingleton.js'
可測試性容易 mock class or static method,彈性高jest 需用 ES module mock,寫法較直覺但彈性較低
熱重載(hot reload)理論支援,instance 維持於 module memory若是 node/hmr,module reload 會讓 singleton 重產
輕鬆支援單元測試可以 new 多次 class,stub static propertymodule pattern 不易在 runtime 換掉

實務建議

  • 單純 config 狀態、純 data 推薦直接用 module 實作 singleton,語法單純。1
  • 需要多參數、OOP 或複雜邏輯/初始化流程,或日後需支援多份變體,用 class 型 singleton 預留彈性較佳。3
  • 若只做單純全域物件共用(如 logger, config, cache),兩種都可行,選團隊習慣即可。

例子簡述

Class Singleton:

class Singleton {
  static #instance = null;
  static getInstance() {
    if (!Singleton.#instance) Singleton.#instance = new Singleton();
    return Singleton.#instance;
  }
}

ES Module Singleton:

// mySingleton.js
const instance = { ... };
export default instance;

兩者共同點是「同一個專案生命週期,只會有一份物件」;差異在於一個用 OOP class 控制,一個靠 module loading/scope 實現唯一性。231

Footnotes

  1. https://pjchender.github.io/pattern/design-pattern-singleton/ 2 3

  2. https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-a-singleton-in-javascript 2

  3. https://refactoring.guru/design-patterns/singleton 2 3