JavaScript 单例模式实现
单例模式确保一个类只有一个实例。
基本实现
闭包实现
function Singleton() { let instance;
function init() { const _instance = { data: '单例数据', method() { console.log('单例方法'); } }; return _instance; }
return { getInstance() { if (!instance) { instance = init(); } return instance; } }; }
const s1 = Singleton.getInstance(); const s2 = Singleton.getInstance();
console.log(s1 === s2); s1.method();
|
模块模式
const Singleton = (function() { let instance;
return { getInstance() { if (!instance) { instance = { data: '单例数据', method() { console.log('单例方法'); } }; } return instance; } }; })();
const s1 = Singleton.getInstance(); const s2 = Singleton.getInstance();
console.log(s1 === s2);
|
ES6 类实现
静态属性
class Singleton { static instance = null;
constructor() { if (Singleton.instance) { return Singleton.instance; } Singleton.instance = this; this.data = '单例数据'; }
method() { console.log('单例方法'); } }
const s1 = new Singleton(); const s2 = new Singleton();
console.log(s1 === s2); s1.method();
|
惰性初始化
const Singleton = { _instance: null,
getInstance() { if (!this._instance) { this._instance = { data: '单例数据', method() { console.log('单例方法'); } }; } return this._instance; } };
const s1 = Singleton.getInstance(); const s2 = Singleton.getInstance();
|
JavaScript 应用场景
1. 全局配置对象
const Config = (function() { const defaultConfig = { apiUrl: 'https://api.example.com', timeout: 5000, retries: 3 };
let currentConfig = { ...defaultConfig };
return { get() { return currentConfig; }, update(newConfig) { currentConfig = { ...currentConfig, ...newConfig }; } }; })();
console.log(Config.get()); Config.update({ timeout: 10000 }); console.log(Config.get());
|
2. 数据库连接池
const Database = { connection: null,
connect(config) { if (!this.connection) { console.log('建立数据库连接'); this.connection = { connect: () => console.log('连接成功'), query: (sql) => console.log(`执行查询: ${sql}`), disconnect: () => console.log('断开连接') }; } return this.connection; } };
const db1 = Database.connect({ host: 'localhost' }); const db2 = Database.connect({ host: 'localhost' });
console.log(db1 === db2); db1.query('SELECT * FROM users');
|
3. 状态管理
const AppState = { user: null, token: null,
setUser(user) { this.user = user; },
setToken(token) { this.token = token; },
getUser() { return this.user; },
getToken() { return this.token; } };
AppState.setUser({ name: '张三' }); AppState.setToken('abc123'); console.log(AppState.getUser()); console.log(AppState.getToken());
|
4. 日志记录器
const Logger = (function() { let instance = null;
function createInstance() { const logger = { info(message) { console.log(`[INFO] ${message}`); }, error(message) { console.error(`[ERROR] ${message}`); }, warn(message) { console.warn(`[WARN] ${message}`); } }; return logger; }
return { getInstance() { if (!instance) { instance = createInstance(); } return instance; } }; })();
const logger1 = Logger.getInstance(); const logger2 = Logger.getInstance();
console.log(logger1 === logger2); logger1.info('应用启动'); logger2.error('发生错误');
|
5. 窗口管理器
const WindowManager = { windows: [],
openWindow(options) { const windowId = Math.random().toString(36).substr(2, 9); const window = { id: windowId, ...options }; this.windows.push(window); console.log(`窗口 ${windowId} 已打开`); return window; },
closeWindow(windowId) { this.windows = this.windows.filter(w => w.id !== windowId); console.log(`窗口 ${windowId} 已关闭`); },
getWindows() { return this.windows; } };
const win1 = WindowManager.openWindow({ title: '窗口1', width: 800 }); const win2 = WindowManager.openWindow({ title: '窗口2', width: 600 }); console.log(WindowManager.getWindows()); WindowManager.closeWindow(win1.id); console.log(WindowManager.getWindows());
|
6. 事件总线
const EventBus = (function() { const events = {};
return { on(event, callback) { if (!events[event]) { events[event] = []; } events[event].push(callback); },
emit(event, data) { if (events[event]) { events[event].forEach(callback => callback(data)); } },
off(event, callback) { if (events[event]) { events[event] = events[event].filter(cb => cb !== callback); } } }; })();
EventBus.on('user:login', (user) => { console.log(`用户登录: ${user.name}`); });
EventBus.emit('user:login', { name: '张三' });
|
7. 消息提示
const Toast = { messages: [],
show(message, type = 'info') { const id = Date.now(); const toast = { id, message, type }; this.messages.push(toast); console.log(`显示提示: ${message}`);
setTimeout(() => { this.messages = this.messages.filter(t => t.id !== id); console.log(`隐藏提示: ${message}`); }, 3000); },
clear() { this.messages = []; } };
Toast.show('操作成功'); Toast.show('操作失败', 'error');
|
8. HTTP 请求封装
const HttpClient = { baseURL: 'https://api.example.com', headers: {},
setBaseURL(url) { this.baseURL = url; },
setHeaders(headers) { this.headers = { ...this.headers, ...headers }; },
async request(method, endpoint, data = null) { const url = `${this.baseURL}${endpoint}`; const options = { method, headers: this.headers };
if (data) { options.body = JSON.stringify(data); }
const response = await fetch(url, options); return response.json(); },
get(endpoint) { return this.request('GET', endpoint); },
post(endpoint, data) { return this.request('POST', endpoint, data); },
put(endpoint, data) { return this.request('PUT', endpoint, data); },
delete(endpoint) { return this.request('DELETE', endpoint); } };
HttpClient.setBaseURL('https://api.example.com/v1'); HttpClient.setHeaders({ 'Content-Type': 'application/json' });
HttpClient.get('/users').then(data => console.log(data)); HttpClient.post('/users', { name: '张三', email: 'zhang@example.com' }) .then(data => console.log(data));
|
9. 本地存储工具
const Storage = { get(key) { try { const item = localStorage.getItem(key); return item ? JSON.parse(item) : null; } catch (error) { console.error('读取存储失败:', error); return null; } },
set(key, value) { try { localStorage.setItem(key, JSON.stringify(value)); } catch (error) { console.error('保存存储失败:', error); } },
remove(key) { localStorage.removeItem(key); },
clear() { localStorage.clear(); } };
Storage.set('user', { name: '张三', age: 25 }); const user = Storage.get('user'); console.log(user); Storage.remove('user');
|
单例 vs 工厂模式
单例模式
const Singleton = { data: '单例数据', method() { console.log('方法'); } };
|
工厂模式
function createInstance(config) { return { data: config.data, method() { console.log('方法'); } }; }
const instance1 = createInstance({ data: '数据1' }); const instance2 = createInstance({ data: '数据2' });
|
单例模式的优缺点
优点
- 全局访问点:提供统一的访问接口
- 控制实例数量:确保只有一个实例
- 共享状态:所有客户端共享同一状态
- 延迟初始化:按需创建实例
缺点
- 全局状态:容易造成状态混乱
- 测试困难:难以进行单元测试
- 耦合度高:与单例紧密耦合
最佳实践
合理使用场景
const Config = { ... }; const AppState = { ... }; const EventBus = { ... };
class UserService { ... } class ProductService { ... }
|
文档注释
避免过度使用
const Everything = { ... };
const Config = { ... }; const Logger = { ... }; const EventBus = { ... };
|
单例模式是 JavaScript 中常见的设计模式,但需要谨慎使用!