getter实现单例的核心是利用其惰性求值特性,在首次访问时创建并缓存实例,后续直接返回;推荐用静态getter+私有字段支持参数配置,避免递归与篡改。

直接在 class 内部用 getter 实现单例,核心是:利用 getter 的惰性求值特性,在首次访问时创建实例并缓存,后续访问直接返回已创建的实例。它轻量、无须额外方法调用、语法简洁,适合配置类、工具类等无需参数初始化的场景。
原理:getter 天然适合延迟加载
JavaScript 中 getter 不会自动执行,只在你读取属性时触发;且可以配合私有字段(#)或闭包隐藏状态,避免外部篡改实例。只要 getter 内部判断“实例是否存在”,不存在就新建并赋值,存在就直接返回——这就是延迟+单例。
基础实现(ES2022+,使用私有字段)
推荐用私有字段存储实例,确保封装性:
class Logger {
#instance = null;
get instance() {
if (this.#instance === null) {
this.#instance = new Logger();
}
return this.#instance;
}
// 私有构造逻辑(防止外部 new)
constructor() {
if (Logger.#initialized) {
throw new Error('Logger is a singleton. Use Logger.instance');
}
Logger.#initialized = true;
// 初始化日志逻辑,如绑定 console、设置 level 等
this.level = 'info';
}
}
Logger.#initialized = false;
使用方式:
const log1 = Logger.instance; // 创建并返回唯一实例 const log2 = Logger.instance; // 直接返回 log1(===) console.log(log1 === log2); // true
更实用的变体:支持初始化参数 & 避免重复构造
若需传参(如配置对象),不能在 getter 里 new 自身(会无限递归)。改用静态 getter + 静态私有字段,让实例归属类本身而非某个对象:
class ApiClient {
static #instance = null;
static #config = null;
static get instance() {
if (ApiClient.#instance === null) {
if (!ApiClient.#config) {
throw new Error('ApiClient.config must be set before first access to instance');
}
ApiClient.#instance = new ApiClient(ApiClient.#config);
}
return ApiClient.#instance;
}
static set config(config) {
if (ApiClient.#instance !== null) {
throw new Error('Cannot reconfigure ApiClient after instance is created');
}
ApiClient.#config = { ...config }; // 浅拷贝防篡改
}
constructor(config) {
this.baseUrl = config.baseUrl || 'https://api.example.com';
this.timeout = config.timeout || 5000;
}
}
使用方式:
- ApiClient.config = { baseUrl: 'https://prod.api' };
- const client = ApiClient.instance;
注意事项与边界情况
这种模式虽轻量,但要注意:
- 无法支持多例或重置(除非手动清空私有字段,不推荐)
- getter 是非枚举、不可写、不可配置的,符合单例语义
- 若 class 有继承需求,静态 getter 更易维护;实例 getter 在子类中可能被覆盖或误用
- 异步初始化(如需 fetch 配置)不适用纯 getter —— 此时应改用 async init() 方法 + Promise 缓存


















