𝑻𝒆𝒏𝑪𝒍𝒂𝒘正在头脑风暴···
𝑻𝒆𝒏𝑲𝒊𝑺𝒆𝒀𝒂の𝑨𝒈𝒆𝒏𝒕助手
𝑻𝒆𝒏-𝒇𝒍𝒂𝒔𝒉

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); // true
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); // true

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); // true
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); // true
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); // true
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' });

单例模式的优缺点

优点

  1. 全局访问点:提供统一的访问接口
  2. 控制实例数量:确保只有一个实例
  3. 共享状态:所有客户端共享同一状态
  4. 延迟初始化:按需创建实例

缺点

  1. 全局状态:容易造成状态混乱
  2. 测试困难:难以进行单元测试
  3. 耦合度高:与单例紧密耦合

最佳实践

  1. 合理使用场景

    // 好:全局配置、状态管理、事件总线
    const Config = { ... };
    const AppState = { ... };
    const EventBus = { ... };

    // 坏:业务逻辑应该创建多个实例
    class UserService { ... }
    class ProductService { ... }
  2. 文档注释

    /**
    * 全局配置管理器
    * 确保配置只有一个实例
    */
    const Config = { ... };
  3. 避免过度使用

    // 不好的做法:滥用单例
    const Everything = { ... }; // 包含所有功能

    // 好的做法:按功能分解
    const Config = { ... };
    const Logger = { ... };
    const EventBus = { ... };

单例模式是 JavaScript 中常见的设计模式,但需要谨慎使用!