JavaScript 中的单例模式(Singleton Pattern)
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。在 JavaScript 中,它常用于管理全局状态、配置对象、缓存等场景。
核心目标
- 确保类只有一个实例。
- 提供全局访问点(如
Singleton.getInstance()
)。
实现方式
以下是几种常见的实现方案:
1. 闭包 + IIFE(经典实现)
javascript
const Singleton = (() => {
let instance; // 私有变量,存储唯一实例
function createInstance() {
// 私有构造函数逻辑
const object = new Object("I am the instance");
return object;
}
return {
getInstance: () => {
if (!instance) {
instance = createInstance(); // 延迟初始化
}
return instance;
},
};
})();
// 使用
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
2. ES6 Class(静态属性版)
javascript
class Singleton {
static instance; // 静态属性存储实例
constructor() {
if (Singleton.instance) {
return Singleton.instance; // 阻止重复创建
}
Singleton.instance = this;
// 初始化逻辑
this.data = "Singleton Data";
}
// 可选:静态方法获取实例
static getInstance() {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
}
// 使用
const obj1 = new Singleton();
const obj2 = new Singleton();
console.log(obj1 === obj2); // true
// 或通过静态方法
const obj3 = Singleton.getInstance();
console.log(obj1 === obj3); // true
3. 模块化(现代推荐方案)
利用 ES6 模块的天然单例特性(模块仅执行一次):
javascript
// singleton.js
let instance;
export default class Singleton {
constructor() {
if (instance) {
return instance;
}
instance = this;
this.state = { count: 0 };
}
increment() {
this.state.count++;
}
}
// 其他文件导入时,总是获得同一个实例
import Singleton from './singleton.js';
const singleton = new Singleton();
关键特性
特性 | 说明 |
---|---|
唯一实例 | 通过闭包/静态属性/模块缓存确保实例唯一性。 |
延迟初始化 | 实例在首次访问时创建(非必须,但常见)。 |
全局访问 | 通过 getInstance() 或模块导入全局访问。 |
阻止直接实例化 | 构造函数内检查实例是否存在,避免 new 重复创建。 |
使用场景
- 全局状态管理:如 Redux Store、Vuex Store。
- 配置对象:应用配置(API 密钥、环境变量)。
- 缓存系统:共享缓存池。
- 日志工具:全局日志实例。
- 数据库连接池:避免重复创建连接。
注意事项
- 测试困难:单例的全局状态可能影响测试隔离性(可通过依赖注入解决)。
- 过度使用风险:滥用会导致代码耦合度高(违背单一职责原则)。
- 多线程问题:JavaScript 是单线程,无需考虑线程安全(Node.js 的 Cluster 模块除外)。
与全局变量的区别
单例模式 | 全局变量 |
---|---|
惰性初始化(按需创建) | 启动时立即初始化 |
封装实现细节 | 暴露所有属性/方法 |
可扩展性(可继承、子类化) | 难以扩展 |
总结
单例模式在 JavaScript 中通过 闭包 、静态属性 或 模块化 实现,是管理全局资源的有效工具。使用时需权衡其便利性与潜在的设计耦合问题。现代前端框架(如 React Context、Vue Provide/Inject)提供了更优雅的状态共享方案,但单例模式在基础库和工具中仍有重要地位。