Skip to content

JavaScript单例模式2024:前端开发者掌握单例设计模式的完整指南

📊 SEO元描述:2024年最新JavaScript单例模式教程,详解单例模式实现方式、应用场景分析、模块单例模式。包含完整实战案例,适合前端开发者掌握创建型设计模式。

核心关键词:JavaScript单例模式2024、单例设计模式、JavaScript设计模式、单例模式实现、模块单例模式、前端设计模式

长尾关键词:JavaScript单例模式怎么实现、单例模式应用场景、JavaScript设计模式最佳实践、前端单例模式优缺点、模块化单例模式实现


📚 JavaScript单例模式学习目标与核心收获

通过本节JavaScript单例模式完整指南,你将系统性掌握:

  • 单例模式核心概念:深入理解单例模式的定义、特点和设计原则
  • 多种实现方式精通:掌握懒汉式、饿汉式、ES6模块等多种单例实现方法
  • 应用场景深度分析:学会识别和应用单例模式的最佳使用场景
  • 模块单例模式:掌握现代JavaScript中基于ES6模块的单例实现
  • 性能优化技巧:理解单例模式的性能优势和潜在问题
  • 实战项目应用:在真实项目中正确应用单例模式解决实际问题

🎯 适合人群

  • 前端开发工程师希望掌握设计模式提升代码质量和架构能力
  • JavaScript高级开发者需要深入理解面向对象编程和设计模式
  • 技术负责人关注代码架构设计和团队开发规范
  • 全栈开发者想要提升软件设计和架构思维能力

🌟 什么是单例模式?为什么单例模式如此重要?

单例模式是什么?这是设计模式中最基础也是最重要的创建型模式之一。单例模式(Singleton Pattern)是指确保一个类只有一个实例,并提供全局访问点的设计模式,也是软件架构设计的重要组成部分。

单例模式的核心价值

  • 🎯 资源控制:确保系统中某些关键资源只有一个实例,避免资源冲突
  • 🔧 全局访问:提供全局访问点,方便在应用的任何地方访问实例
  • 💡 内存优化:避免重复创建对象,节省内存空间和创建开销
  • 📚 状态管理:维护全局状态,确保数据的一致性
  • 🚀 性能提升:减少对象创建和销毁的开销,提升应用性能

💡 设计模式建议:单例模式是23种设计模式中使用频率最高的模式之一,在前端开发中广泛应用于配置管理、缓存系统、日志记录等场景。

单例模式的实现方式:从基础到高级

单例模式有多种实现方式,每种方式都有其特点和适用场景。

javascript
// 🎉 基础单例模式实现
class BasicSingleton {
    constructor() {
        // 如果实例已存在,返回现有实例
        if (BasicSingleton.instance) {
            return BasicSingleton.instance;
        }
        
        // 初始化实例
        this.timestamp = Date.now();
        this.data = new Map();
        
        // 保存实例引用
        BasicSingleton.instance = this;
        
        return this;
    }
    
    // 获取实例的静态方法
    static getInstance() {
        if (!BasicSingleton.instance) {
            BasicSingleton.instance = new BasicSingleton();
        }
        return BasicSingleton.instance;
    }
    
    // 业务方法
    setData(key, value) {
        this.data.set(key, value);
    }
    
    getData(key) {
        return this.data.get(key);
    }
    
    getAllData() {
        return Object.fromEntries(this.data);
    }
}

// 🎉 懒汉式单例模式(延迟初始化)
class LazySingleton {
    constructor() {
        if (LazySingleton.instance) {
            return LazySingleton.instance;
        }
        
        this.initialized = false;
        LazySingleton.instance = this;
        
        return this;
    }
    
    // 延迟初始化
    init() {
        if (!this.initialized) {
            console.log('Lazy Singleton initializing...');
            this.config = {
                apiUrl: 'https://api.example.com',
                timeout: 5000,
                retries: 3
            };
            this.cache = new Map();
            this.initialized = true;
        }
        return this;
    }
    
    static getInstance() {
        if (!LazySingleton.instance) {
            LazySingleton.instance = new LazySingleton();
        }
        return LazySingleton.instance.init();
    }
    
    getConfig(key) {
        return this.config[key];
    }
    
    setConfig(key, value) {
        this.config[key] = value;
    }
    
    cache(key, value) {
        if (value !== undefined) {
            this.cache.set(key, value);
        }
        return this.cache.get(key);
    }
}

// 🎉 饿汉式单例模式(立即初始化)
class EagerSingleton {
    constructor() {
        if (EagerSingleton.instance) {
            return EagerSingleton.instance;
        }
        
        // 立即初始化
        this.initialize();
        EagerSingleton.instance = this;
        
        return this;
    }
    
    initialize() {
        console.log('Eager Singleton initializing...');
        this.startTime = Date.now();
        this.eventBus = new Map();
        this.subscribers = new Map();
        
        // 设置定时器或其他初始化逻辑
        this.heartbeat = setInterval(() => {
            this.emit('heartbeat', { timestamp: Date.now() });
        }, 10000);
    }
    
    static getInstance() {
        if (!EagerSingleton.instance) {
            EagerSingleton.instance = new EagerSingleton();
        }
        return EagerSingleton.instance;
    }
    
    // 事件发布订阅功能
    on(event, callback) {
        if (!this.subscribers.has(event)) {
            this.subscribers.set(event, []);
        }
        this.subscribers.get(event).push(callback);
    }
    
    off(event, callback) {
        if (this.subscribers.has(event)) {
            const callbacks = this.subscribers.get(event);
            const index = callbacks.indexOf(callback);
            if (index > -1) {
                callbacks.splice(index, 1);
            }
        }
    }
    
    emit(event, data) {
        if (this.subscribers.has(event)) {
            this.subscribers.get(event).forEach(callback => {
                try {
                    callback(data);
                } catch (error) {
                    console.error('Event callback error:', error);
                }
            });
        }
    }
    
    destroy() {
        if (this.heartbeat) {
            clearInterval(this.heartbeat);
        }
        this.subscribers.clear();
        EagerSingleton.instance = null;
    }
}

// 🎉 线程安全的单例模式(使用闭包)
const ThreadSafeSingleton = (function() {
    let instance = null;
    let isCreating = false;
    
    function Singleton() {
        // 防止通过new直接创建
        if (isCreating === false) {
            throw new Error('Cannot construct singleton');
        }
        
        this.id = Math.random().toString(36).substr(2, 9);
        this.createdAt = new Date();
        this.resources = new Map();
    }
    
    Singleton.prototype.addResource = function(key, resource) {
        this.resources.set(key, resource);
    };
    
    Singleton.prototype.getResource = function(key) {
        return this.resources.get(key);
    };
    
    Singleton.prototype.removeResource = function(key) {
        return this.resources.delete(key);
    };
    
    Singleton.prototype.getInfo = function() {
        return {
            id: this.id,
            createdAt: this.createdAt,
            resourceCount: this.resources.size
        };
    };
    
    return {
        getInstance: function() {
            if (instance === null) {
                isCreating = true;
                instance = new Singleton();
                isCreating = false;
            }
            return instance;
        },
        
        hasInstance: function() {
            return instance !== null;
        },
        
        destroyInstance: function() {
            if (instance) {
                instance.resources.clear();
                instance = null;
            }
        }
    };
})();

// 🎉 高级单例模式 - 支持参数化创建
class ParameterizedSingleton {
    constructor(config = {}) {
        const key = JSON.stringify(config);
        
        // 基于配置参数创建不同的实例
        if (ParameterizedSingleton.instances.has(key)) {
            return ParameterizedSingleton.instances.get(key);
        }
        
        this.config = {
            name: 'default',
            version: '1.0.0',
            debug: false,
            ...config
        };
        
        this.initialize();
        
        ParameterizedSingleton.instances.set(key, this);
        return this;
    }
    
    static instances = new Map();
    
    initialize() {
        this.logger = this.createLogger();
        this.storage = this.createStorage();
        this.metrics = {
            created: Date.now(),
            operations: 0,
            errors: 0
        };
        
        if (this.config.debug) {
            console.log(`Singleton created with config:`, this.config);
        }
    }
    
    createLogger() {
        return {
            log: (message, ...args) => {
                if (this.config.debug) {
                    console.log(`[${this.config.name}]`, message, ...args);
                }
            },
            error: (message, ...args) => {
                console.error(`[${this.config.name}]`, message, ...args);
                this.metrics.errors++;
            }
        };
    }
    
    createStorage() {
        const storageKey = `singleton_${this.config.name}`;
        
        return {
            get: (key) => {
                try {
                    const data = localStorage.getItem(`${storageKey}_${key}`);
                    return data ? JSON.parse(data) : null;
                } catch (error) {
                    this.logger.error('Storage get error:', error);
                    return null;
                }
            },
            
            set: (key, value) => {
                try {
                    localStorage.setItem(`${storageKey}_${key}`, JSON.stringify(value));
                    this.metrics.operations++;
                    return true;
                } catch (error) {
                    this.logger.error('Storage set error:', error);
                    return false;
                }
            },
            
            remove: (key) => {
                try {
                    localStorage.removeItem(`${storageKey}_${key}`);
                    this.metrics.operations++;
                    return true;
                } catch (error) {
                    this.logger.error('Storage remove error:', error);
                    return false;
                }
            }
        };
    }
    
    static getInstance(config = {}) {
        return new ParameterizedSingleton(config);
    }
    
    static getInstanceByName(name) {
        for (const [key, instance] of ParameterizedSingleton.instances) {
            const config = JSON.parse(key);
            if (config.name === name) {
                return instance;
            }
        }
        return null;
    }
    
    static getAllInstances() {
        return Array.from(ParameterizedSingleton.instances.values());
    }
    
    static clearInstances() {
        ParameterizedSingleton.instances.clear();
    }
    
    getMetrics() {
        return {
            ...this.metrics,
            uptime: Date.now() - this.metrics.created
        };
    }
    
    updateConfig(newConfig) {
        this.config = { ...this.config, ...newConfig };
        this.logger.log('Config updated:', this.config);
    }
}

// 使用示例
console.log('=== 基础单例模式测试 ===');
const singleton1 = new BasicSingleton();
const singleton2 = BasicSingleton.getInstance();
console.log('Same instance:', singleton1 === singleton2); // true

singleton1.setData('user', { name: 'John', age: 30 });
console.log('Data from singleton2:', singleton2.getData('user'));

console.log('=== 懒汉式单例模式测试 ===');
const lazySingleton1 = LazySingleton.getInstance();
const lazySingleton2 = LazySingleton.getInstance();
console.log('Lazy singletons same:', lazySingleton1 === lazySingleton2); // true

lazySingleton1.setConfig('apiUrl', 'https://new-api.example.com');
console.log('Config from lazy2:', lazySingleton2.getConfig('apiUrl'));

console.log('=== 饿汉式单例模式测试 ===');
const eagerSingleton = EagerSingleton.getInstance();
eagerSingleton.on('heartbeat', (data) => {
    console.log('Heartbeat received:', data.timestamp);
});

console.log('=== 线程安全单例模式测试 ===');
const threadSafeSingleton = ThreadSafeSingleton.getInstance();
threadSafeSingleton.addResource('database', { connection: 'active' });
console.log('Thread safe singleton info:', threadSafeSingleton.getInfo());

console.log('=== 参数化单例模式测试 ===');
const paramSingleton1 = ParameterizedSingleton.getInstance({ name: 'app1', debug: true });
const paramSingleton2 = ParameterizedSingleton.getInstance({ name: 'app2', debug: false });
const paramSingleton3 = ParameterizedSingleton.getInstance({ name: 'app1', debug: true });

console.log('Param singleton1 === singleton3:', paramSingleton1 === paramSingleton3); // true
console.log('Param singleton1 === singleton2:', paramSingleton1 === paramSingleton2); // false

paramSingleton1.storage.set('test', { value: 123 });
console.log('Storage test:', paramSingleton1.storage.get('test'));

单例模式实现方式对比

  • 基础实现:简单直接,适合小型项目
  • 懒汉式:延迟初始化,节省资源,适合重型对象
  • 饿汉式:立即初始化,线程安全,适合必需的服务
  • 线程安全:使用闭包防止意外创建,更加安全
  • 参数化:支持多实例管理,适合复杂应用场景

应用场景分析:何时使用单例模式

什么场景适合使用单例模式?如何正确应用?

单例模式的典型应用场景包括配置管理、缓存系统、日志记录、数据库连接池等需要全局唯一实例的场景:

javascript
// 🎉 实际应用场景示例

// 1. 配置管理器
class ConfigManager {
    constructor() {
        if (ConfigManager.instance) {
            return ConfigManager.instance;
        }
        
        this.config = {};
        this.watchers = new Map();
        this.loadConfig();
        
        ConfigManager.instance = this;
        return this;
    }
    
    async loadConfig() {
        try {
            // 从多个来源加载配置
            const defaultConfig = await this.loadDefaultConfig();
            const envConfig = await this.loadEnvironmentConfig();
            const userConfig = await this.loadUserConfig();
            
            this.config = {
                ...defaultConfig,
                ...envConfig,
                ...userConfig
            };
            
            this.notifyWatchers('config-loaded', this.config);
        } catch (error) {
            console.error('Failed to load config:', error);
        }
    }
    
    async loadDefaultConfig() {
        return {
            apiUrl: 'https://api.example.com',
            timeout: 5000,
            retries: 3,
            theme: 'light',
            language: 'en'
        };
    }
    
    async loadEnvironmentConfig() {
        // 从环境变量或环境配置文件加载
        return {
            apiUrl: process.env.API_URL || 'https://api.example.com',
            debug: process.env.NODE_ENV === 'development'
        };
    }
    
    async loadUserConfig() {
        // 从用户设置或本地存储加载
        try {
            const userConfig = localStorage.getItem('userConfig');
            return userConfig ? JSON.parse(userConfig) : {};
        } catch {
            return {};
        }
    }
    
    get(key, defaultValue = null) {
        return this.config[key] !== undefined ? this.config[key] : defaultValue;
    }
    
    set(key, value) {
        const oldValue = this.config[key];
        this.config[key] = value;
        
        // 持久化用户配置
        this.saveUserConfig();
        
        // 通知观察者
        this.notifyWatchers('config-changed', { key, value, oldValue });
    }
    
    watch(event, callback) {
        if (!this.watchers.has(event)) {
            this.watchers.set(event, []);
        }
        this.watchers.get(event).push(callback);
    }
    
    unwatch(event, callback) {
        if (this.watchers.has(event)) {
            const callbacks = this.watchers.get(event);
            const index = callbacks.indexOf(callback);
            if (index > -1) {
                callbacks.splice(index, 1);
            }
        }
    }
    
    notifyWatchers(event, data) {
        if (this.watchers.has(event)) {
            this.watchers.get(event).forEach(callback => {
                try {
                    callback(data);
                } catch (error) {
                    console.error('Config watcher error:', error);
                }
            });
        }
    }
    
    saveUserConfig() {
        try {
            const userConfig = {
                theme: this.config.theme,
                language: this.config.language,
                // 只保存用户可配置的项目
            };
            localStorage.setItem('userConfig', JSON.stringify(userConfig));
        } catch (error) {
            console.error('Failed to save user config:', error);
        }
    }
    
    static getInstance() {
        if (!ConfigManager.instance) {
            ConfigManager.instance = new ConfigManager();
        }
        return ConfigManager.instance;
    }
}

// 2. 缓存管理器
class CacheManager {
    constructor() {
        if (CacheManager.instance) {
            return CacheManager.instance;
        }
        
        this.cache = new Map();
        this.ttlMap = new Map();
        this.maxSize = 1000;
        this.defaultTTL = 300000; // 5分钟
        
        this.startCleanupTimer();
        
        CacheManager.instance = this;
        return this;
    }
    
    set(key, value, ttl = this.defaultTTL) {
        // 检查缓存大小限制
        if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
            this.evictOldest();
        }
        
        this.cache.set(key, {
            value,
            timestamp: Date.now(),
            accessCount: 0
        });
        
        if (ttl > 0) {
            this.ttlMap.set(key, Date.now() + ttl);
        }
        
        return this;
    }
    
    get(key) {
        if (!this.cache.has(key)) {
            return null;
        }
        
        // 检查TTL
        if (this.ttlMap.has(key) && Date.now() > this.ttlMap.get(key)) {
            this.delete(key);
            return null;
        }
        
        const item = this.cache.get(key);
        item.accessCount++;
        item.lastAccess = Date.now();
        
        return item.value;
    }
    
    has(key) {
        return this.cache.has(key) && 
               (!this.ttlMap.has(key) || Date.now() <= this.ttlMap.get(key));
    }
    
    delete(key) {
        this.cache.delete(key);
        this.ttlMap.delete(key);
        return this;
    }
    
    clear() {
        this.cache.clear();
        this.ttlMap.clear();
        return this;
    }
    
    evictOldest() {
        // LRU淘汰策略
        let oldestKey = null;
        let oldestTime = Date.now();
        
        for (const [key, item] of this.cache) {
            const lastAccess = item.lastAccess || item.timestamp;
            if (lastAccess < oldestTime) {
                oldestTime = lastAccess;
                oldestKey = key;
            }
        }
        
        if (oldestKey) {
            this.delete(oldestKey);
        }
    }
    
    startCleanupTimer() {
        setInterval(() => {
            this.cleanup();
        }, 60000); // 每分钟清理一次
    }
    
    cleanup() {
        const now = Date.now();
        const expiredKeys = [];
        
        for (const [key, expireTime] of this.ttlMap) {
            if (now > expireTime) {
                expiredKeys.push(key);
            }
        }
        
        expiredKeys.forEach(key => this.delete(key));
    }
    
    getStats() {
        return {
            size: this.cache.size,
            maxSize: this.maxSize,
            hitRate: this.calculateHitRate(),
            memoryUsage: this.estimateMemoryUsage()
        };
    }
    
    calculateHitRate() {
        let totalAccess = 0;
        for (const item of this.cache.values()) {
            totalAccess += item.accessCount;
        }
        return totalAccess > 0 ? (this.cache.size / totalAccess) * 100 : 0;
    }
    
    estimateMemoryUsage() {
        let size = 0;
        for (const [key, item] of this.cache) {
            size += key.length * 2; // 字符串大小估算
            size += JSON.stringify(item.value).length * 2;
        }
        return size;
    }
    
    static getInstance() {
        if (!CacheManager.instance) {
            CacheManager.instance = new CacheManager();
        }
        return CacheManager.instance;
    }
}

// 3. 日志管理器
class Logger {
    constructor() {
        if (Logger.instance) {
            return Logger.instance;
        }
        
        this.logs = [];
        this.maxLogs = 1000;
        this.logLevel = 'info';
        this.outputs = ['console'];
        
        Logger.instance = this;
        return this;
    }
    
    setLevel(level) {
        this.logLevel = level;
        return this;
    }
    
    addOutput(output) {
        if (!this.outputs.includes(output)) {
            this.outputs.push(output);
        }
        return this;
    }
    
    log(level, message, ...args) {
        const logEntry = {
            timestamp: new Date().toISOString(),
            level,
            message,
            args,
            stack: new Error().stack
        };
        
        // 添加到内存日志
        this.logs.push(logEntry);
        if (this.logs.length > this.maxLogs) {
            this.logs.shift();
        }
        
        // 输出到各个目标
        this.outputs.forEach(output => {
            this.outputLog(output, logEntry);
        });
    }
    
    outputLog(output, logEntry) {
        const { timestamp, level, message, args } = logEntry;
        const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
        
        switch (output) {
            case 'console':
                console[level] ? console[level](formattedMessage, ...args) : 
                                console.log(formattedMessage, ...args);
                break;
            case 'localStorage':
                this.saveToLocalStorage(logEntry);
                break;
            case 'server':
                this.sendToServer(logEntry);
                break;
        }
    }
    
    saveToLocalStorage(logEntry) {
        try {
            const logs = JSON.parse(localStorage.getItem('app_logs') || '[]');
            logs.push(logEntry);
            if (logs.length > 100) {
                logs.splice(0, logs.length - 100);
            }
            localStorage.setItem('app_logs', JSON.stringify(logs));
        } catch (error) {
            console.error('Failed to save log to localStorage:', error);
        }
    }
    
    async sendToServer(logEntry) {
        try {
            await fetch('/api/logs', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(logEntry)
            });
        } catch (error) {
            console.error('Failed to send log to server:', error);
        }
    }
    
    debug(message, ...args) {
        this.log('debug', message, ...args);
    }
    
    info(message, ...args) {
        this.log('info', message, ...args);
    }
    
    warn(message, ...args) {
        this.log('warn', message, ...args);
    }
    
    error(message, ...args) {
        this.log('error', message, ...args);
    }
    
    getLogs(level = null, limit = 100) {
        let filteredLogs = this.logs;
        
        if (level) {
            filteredLogs = this.logs.filter(log => log.level === level);
        }
        
        return filteredLogs.slice(-limit);
    }
    
    clearLogs() {
        this.logs = [];
        return this;
    }
    
    static getInstance() {
        if (!Logger.instance) {
            Logger.instance = new Logger();
        }
        return Logger.instance;
    }
}

// 使用示例
const config = ConfigManager.getInstance();
const cache = CacheManager.getInstance();
const logger = Logger.getInstance();

// 配置管理
config.watch('config-changed', ({ key, value }) => {
    logger.info(`Config changed: ${key} = ${value}`);
});

config.set('theme', 'dark');
console.log('Current theme:', config.get('theme'));

// 缓存管理
cache.set('user:123', { name: 'John', email: 'john@example.com' }, 60000);
console.log('Cached user:', cache.get('user:123'));

// 日志记录
logger.addOutput('localStorage');
logger.info('Application started');
logger.warn('This is a warning message');
logger.error('This is an error message');

console.log('Recent logs:', logger.getLogs('info', 5));

单例模式应用场景总结

  • 🎯 配置管理:全局配置信息的统一管理和访问
  • 🎯 缓存系统:应用级缓存的统一管理和控制
  • 🎯 日志记录:统一的日志收集、格式化和输出
  • 🎯 数据库连接:数据库连接池的管理和复用
  • 🎯 状态管理:应用全局状态的统一管理

💼 最佳实践:单例模式适用于需要全局唯一实例的场景,但要避免过度使用,以免造成代码耦合度过高。在现代JavaScript开发中,ES6模块本身就提供了单例特性。


📚 JavaScript单例模式学习总结与下一步规划

✅ 本节核心收获回顾

通过本节JavaScript单例模式完整指南的学习,你已经掌握:

  1. 单例模式核心概念:深入理解了单例模式的定义、特点和设计原则
  2. 多种实现方式精通:掌握了懒汉式、饿汉式、ES6模块等多种单例实现方法
  3. 应用场景深度分析:学会了识别和应用单例模式的最佳使用场景
  4. 实战项目应用:在配置管理、缓存系统、日志记录等场景中正确应用单例模式
  5. 性能优化技巧:理解了单例模式的性能优势和潜在问题

🎯 单例模式下一步

  1. 工厂模式学习:学习工厂模式与单例模式的结合应用
  2. 依赖注入模式:了解现代框架中的依赖注入和单例管理
  3. 模块化设计:深入学习ES6模块系统中的单例应用
  4. 测试策略:学习如何测试单例模式的代码

🔗 相关学习资源

  • 设计模式经典书籍:《设计模式:可复用面向对象软件的基础》
  • JavaScript设计模式:《JavaScript设计模式与开发实践》
  • 现代JavaScript架构:学习现代前端框架中的设计模式应用
  • 代码质量工具:ESLint、SonarJS等代码质量检测工具

💪 实践建议

  1. 识别应用场景:在实际项目中识别适合使用单例模式的场景
  2. 重构现有代码:将现有的全局对象重构为单例模式
  3. 性能测试:对比单例模式和普通对象创建的性能差异
  4. 团队规范:建立团队的单例模式使用规范和最佳实践

🔍 常见问题FAQ

Q1: 单例模式和全局变量有什么区别?

A: 单例模式提供了更好的封装性和控制性,可以延迟初始化、控制访问权限、提供业务方法。全局变量容易被意外修改,缺乏封装性。单例模式是更好的全局访问解决方案。

Q2: 在什么情况下不应该使用单例模式?

A: 当对象需要多个实例、需要继承、或者会导致过度耦合时不应使用单例模式。另外,单例模式会增加测试难度,在需要频繁测试的场景中要谨慎使用。

Q3: ES6模块是否已经提供了单例功能?

A: 是的,ES6模块在首次导入时会创建实例,后续导入会返回同一个实例,这本身就是单例模式。在现代JavaScript开发中,可以优先考虑使用模块单例。

Q4: 如何测试单例模式的代码?

A: 可以在测试前重置单例实例、使用依赖注入、或者提供测试专用的重置方法。也可以将单例的业务逻辑提取到单独的类中,只对业务逻辑进行测试。

Q5: 单例模式在多线程环境下有什么问题?

A: JavaScript是单线程的,但在Web Workers环境下需要注意。每个Worker都有独立的全局作用域,单例实例不会共享。如果需要跨Worker共享数据,需要使用其他机制。


🛠️ 单例模式工具使用指南

常见问题解决方案

单例实例重置问题

javascript
// 问题:测试时需要重置单例实例
// 解决:提供重置方法

class TestableSingleton {
    constructor() {
        if (TestableSingleton.instance) {
            return TestableSingleton.instance;
        }
        this.data = new Map();
        TestableSingleton.instance = this;
        return this;
    }
    
    static getInstance() {
        if (!TestableSingleton.instance) {
            TestableSingleton.instance = new TestableSingleton();
        }
        return TestableSingleton.instance;
    }
    
    // 测试专用重置方法
    static resetInstance() {
        TestableSingleton.instance = null;
    }
}

单例模式内存泄漏处理

javascript
// 问题:单例模式可能导致内存泄漏
// 解决:提供清理机制

class CleanableSingleton {
    constructor() {
        if (CleanableSingleton.instance) {
            return CleanableSingleton.instance;
        }
        
        this.timers = [];
        this.listeners = [];
        this.resources = new Map();
        
        CleanableSingleton.instance = this;
        return this;
    }
    
    addTimer(timer) {
        this.timers.push(timer);
    }
    
    addListener(element, event, handler) {
        element.addEventListener(event, handler);
        this.listeners.push({ element, event, handler });
    }
    
    cleanup() {
        // 清理定时器
        this.timers.forEach(timer => clearInterval(timer));
        this.timers = [];
        
        // 清理事件监听器
        this.listeners.forEach(({ element, event, handler }) => {
            element.removeEventListener(event, handler);
        });
        this.listeners = [];
        
        // 清理资源
        this.resources.clear();
    }
    
    static destroy() {
        if (CleanableSingleton.instance) {
            CleanableSingleton.instance.cleanup();
            CleanableSingleton.instance = null;
        }
    }
}

"掌握单例模式,让你的代码拥有更好的架构设计和资源管理能力。每一个设计模式的应用,都是对代码质量的提升!"