前言
单例模式是 JavaScript 设计模式中最常用也最基础的一种,今天我们就来深入探讨它的奥秘!
1. 什么是单例模式? 🤔
单例模式(Singleton Pattern)是一种创建型设计模式 ,它确保一个类只有一个实例 ,并提供一个全局访问点来获取这个实例。
简单来说:
- 你只能创建一个对象
- 无论你尝试创建多少次,得到的都是同一个对象
- 就像你家的电视机遥控器,不管谁要用,都只能拿那一个
2. 为什么要用单例模式? 🧐
单例模式的设计目的主要有以下几点:
- 节省资源:避免重复创建相同对象,减少内存开销
- 全局访问:提供一个统一的访问点,方便管理
- 数据一致性:确保所有代码操作的是同一个实例,避免数据不一致
- 性能优化:减少不必要的对象创建和销毁过程
常见应用场景:
- 全局配置对象
- 缓存系统
- 浏览器中的 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')); // "张三"
关键点解析:
static instance
静态属性保存唯一实例- 构造函数中检查是否已有实例
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"
关键点解析:
- 使用 IIFE(立即执行函数)创建闭包
- 闭包内的
instance
变量保存唯一实例 - 返回的函数充当构造函数,控制实例创建
4. 考点和面试题 🔍
常见面试题1:实现一个单例模式
答案:见上面实现代码
常见面试题2:单例模式的优缺点
答案:
- 优点:
- 减少内存开销
- 避免资源多重占用
- 提供全局访问点
- 缺点:
- 难以扩展(通常需要修改源代码)
- 与单一职责原则冲突(既要管理实例又要处理业务)
- 测试困难(全局状态难以隔离)
常见面试题3:如何防止单例被破坏?
答案:
-
防止通过构造函数创建:
javascriptconstructor() { if (Storage.instance) { throw new Error("请使用getInstance方法获取实例"); } // ... }
-
防止通过克隆破坏:
javascriptclass Storage { // ...其他代码 clone() { return this; } // 或者使用Symbol.species static get [Symbol.species]() { return this; } }
5. 总结 📚
单例模式是 JavaScript 中最实用的设计模式之一:
✅ 优点:
- 节省内存资源
- 确保全局唯一性
- 提供集中管理
⚠️ 注意事项:
- 不要滥用,可能导致代码耦合
- 注意线程安全(在JS中通常不是问题)
- 考虑测试的便利性
💡 最佳实践:
- 优先使用 ES6 Class 实现
- 考虑是否需要惰性加载
- 为单例添加清晰的文档说明
记住:设计模式是工具,不是教条,要根据实际场景灵活运用!🎯
希望这篇博客能帮助你彻底掌握 JavaScript 单例模式!如果有任何问题,欢迎留言讨论~ 💬