JavaScript 设计模式之单例模式🚀

前言

单例模式是 JavaScript 设计模式中最常用也最基础的一种,今天我们就来深入探讨它的奥秘!

1. 什么是单例模式? 🤔

单例模式(Singleton Pattern)是一种创建型设计模式 ,它确保一个类只有一个实例 ,并提供一个全局访问点来获取这个实例。

简单来说:

  • 你只能创建一个对象
  • 无论你尝试创建多少次,得到的都是同一个对象
  • 就像你家的电视机遥控器,不管谁要用,都只能拿那一个

2. 为什么要用单例模式? 🧐

单例模式的设计目的主要有以下几点:

  1. 节省资源:避免重复创建相同对象,减少内存开销
  2. 全局访问:提供一个统一的访问点,方便管理
  3. 数据一致性:确保所有代码操作的是同一个实例,避免数据不一致
  4. 性能优化:减少不必要的对象创建和销毁过程

常见应用场景:

  • 全局配置对象
  • 缓存系统
  • 浏览器中的 localStorage/sessionStorage 封装
  • 数据库连接池
  • 状态管理(如 Vuex、Redux)

3. 如何实现单例模式? 💻

方法1:ES6 Class 实现(现代方式)

javascript 复制代码
class Storage {
    static instance = null; // 静态属性,存储唯一实例
    
    constructor() {
        if (Storage.instance) {
            return Storage.instance; // 如果已存在实例,直接返回
        }
        Storage.instance = this; // 否则将当前实例赋值给静态属性
    }
    
    // 静态方法获取实例
    static getInstance() {
        if (!Storage.instance) {
            Storage.instance = new Storage();
        }
        return Storage.instance;
    }
    
    // 实例方法
    getItem(key) {
        return localStorage.getItem(key);
    }
    
    setItem(key, value) {
        localStorage.setItem(key, value);
    }
}

// 测试
const storage1 = Storage.getInstance();
const storage2 = Storage.getInstance();
console.log(storage1 === storage2); // true ✅
storage1.setItem('name', '张三');
console.log(storage2.getItem('name')); // "张三"

关键点解析

  1. static instance 静态属性保存唯一实例
  2. 构造函数中检查是否已有实例
  3. getInstance() 静态方法提供全局访问点,即使不用实例化也可以直接调用这个函数

方法2:闭包实现(传统方式)

javascript 复制代码
// 基础构造函数
function StorageBase() {}

// 添加原型方法
StorageBase.prototype.getItem = function(key) {
    return localStorage.getItem(key);
};
StorageBase.prototype.setItem = function(key, value) {
    localStorage.setItem(key, value);
};

// 使用闭包实现单例
const Storage = (function() {
    let instance = null; // 闭包保存的唯一实例
    
    return function() {
        if (!instance) {
            instance = new StorageBase();
        }
        return instance;
    };
})();

// 测试
const storage1 = new Storage();
const storage2 = new Storage();
console.log(storage1 === storage2); // true ✅
storage1.setItem('age', '25');
console.log(storage2.getItem('age')); // "25"

关键点解析

  1. 使用 IIFE(立即执行函数)创建闭包
  2. 闭包内的 instance 变量保存唯一实例
  3. 返回的函数充当构造函数,控制实例创建

4. 考点和面试题 🔍

常见面试题1:实现一个单例模式

答案:见上面实现代码

常见面试题2:单例模式的优缺点

答案

  • 优点:
    • 减少内存开销
    • 避免资源多重占用
    • 提供全局访问点
  • 缺点:
    • 难以扩展(通常需要修改源代码)
    • 与单一职责原则冲突(既要管理实例又要处理业务)
    • 测试困难(全局状态难以隔离)

常见面试题3:如何防止单例被破坏?

答案

  1. 防止通过构造函数创建:

    javascript 复制代码
    constructor() {
        if (Storage.instance) {
            throw new Error("请使用getInstance方法获取实例");
        }
        // ...
    }
  2. 防止通过克隆破坏:

    javascript 复制代码
    class Storage {
     // ...其他代码
     
     clone() {
         return this;
     }
    
     // 或者使用Symbol.species
     static get [Symbol.species]() {
         return this;
     }
    }

5. 总结 📚

单例模式是 JavaScript 中最实用的设计模式之一:

优点

  • 节省内存资源
  • 确保全局唯一性
  • 提供集中管理

⚠️ 注意事项

  • 不要滥用,可能导致代码耦合
  • 注意线程安全(在JS中通常不是问题)
  • 考虑测试的便利性

💡 最佳实践

  • 优先使用 ES6 Class 实现
  • 考虑是否需要惰性加载
  • 为单例添加清晰的文档说明

记住:设计模式是工具,不是教条,要根据实际场景灵活运用!🎯


希望这篇博客能帮助你彻底掌握 JavaScript 单例模式!如果有任何问题,欢迎留言讨论~ 💬

相关推荐
工业甲酰苯胺2 小时前
TypeScript枚举类型应用:前后端状态码映射的最简方案
javascript·typescript·状态模式
brzhang2 小时前
我操,终于有人把 AI 大佬们 PUA 程序员的套路给讲明白了!
前端·后端·架构
止观止3 小时前
React虚拟DOM的进化之路
前端·react.js·前端框架·reactjs·react
goms3 小时前
前端项目集成lint-staged
前端·vue·lint-staged
谢尔登3 小时前
【React Natve】NetworkError 和 TouchableOpacity 组件
前端·react.js·前端框架
Lin Hsüeh-ch'in3 小时前
如何彻底禁用 Chrome 自动更新
前端·chrome
augenstern4165 小时前
HTML面试题
前端·html
张可5 小时前
一个KMP/CMP项目的组织结构和集成方式
android·前端·kotlin
G等你下课5 小时前
React 路由懒加载入门:提升首屏性能的第一步
前端·react.js·前端框架
谢尔登6 小时前
【React Native】ScrollView 和 FlatList 组件
javascript·react native·react.js