从0开始学习JavaScript--JavaScript 单例模式

单例模式是一种常见的设计模式,它保证一个类仅有一个实例,并提供一个全局访问点。在 JavaScript 中,单例模式通常用于创建唯一的对象,以确保全局只有一个实例。本文将深入探讨单例模式的基本概念、实现方式,以及在实际应用中的各种场景。

单例模式的基本概念

单例模式的核心思想是确保一个类只有一个实例,并提供一个全局访问点。这样做的好处包括:

  1. 资源共享: 由于只有一个实例,可以避免多次创建相同对象,减少内存占用。
  2. 全局访问: 通过单一的入口访问对象,方便管理和控制。

在 JavaScript 中,实现单例模式有多种方式,我们将分别介绍其中的三种:懒汉式、饿汉式和模块模式。

懒汉式单例模式

懒汉式单例模式是指在需要时才创建实例,如果实例已经存在,则返回现有实例。这样可以延迟对象的创建,提高性能。

示例代码:

class LazySingleton {constructor() {if (!LazySingleton.instance) {this.data = Math.random(); // 示例中添加随机数,表示实例的一些数据LazySingleton.instance = this;}return LazySingleton.instance;}
}const instance1 = new LazySingleton();
const instance2 = new LazySingleton();console.log(instance1 === instance2); // 输出: true
console.log(instance1.data === instance2.data); // 输出: true

在这个示例中,LazySingleton 类只有在实例不存在时才创建新实例。之后,无论创建多少次实例,都返回第一次创建的实例。

饿汉式单例模式

饿汉式单例模式是指在应用启动时就立即创建实例,无论后续是否会使用到。

示例代码:

class EagerSingleton {constructor() {if (!EagerSingleton.instance) {this.data = Math.random();EagerSingleton.instance = this;}return EagerSingleton.instance;}
}const instance1 = new EagerSingleton();
const instance2 = new EagerSingleton();console.log(instance1 === instance2); // 输出: true
console.log(instance1.data === instance2.data); // 输出: true

在这个示例中,EagerSingleton 类在第一次创建实例时就立即创建了一个实例。之后,无论创建多少次实例,都返回第一次创建的实例。

模块模式的单例

模块模式是一种结合了闭包和立即调用函数表达式(IIFE)的方式,创建单例的模式。

示例代码:

const ModuleSingleton = (function () {let instance;function createInstance() {return {data: Math.random()};}return {getInstance: function () {if (!instance) {instance = createInstance();}return instance;}};
})();const instance1 = ModuleSingleton.getInstance();
const instance2 = ModuleSingleton.getInstance();console.log(instance1 === instance2); // 输出: true
console.log(instance1.data === instance2.data); // 输出: true

在这个示例中,ModuleSingleton 使用闭包和 IIFE 创建了一个包含 getInstance 方法的模块。getInstance 方法确保只有一个实例被创建,并提供全局访问点。

单例模式的实际应用场景

1. 管理全局状态

单例模式常用于管理全局状态,确保整个应用中只有一个状态管理实例,例如 Redux 中的 store。

const store = createStore(reducer);

2. 数据缓存

在需要缓存数据的场景,可以使用单例模式确保只有一个缓存实例。

class DataCache {constructor() {if (!DataCache.instance) {this.cache = {};DataCache.instance = this;}return DataCache.instance;}set(key, value) {this.cache[key] = value;}get(key) {return this.cache[key];}
}const cache = new DataCache();
cache.set('user', { name: 'John' });
console.log(cache.get('user')); // 输出: { name: 'John' }

3. 配置管理

在配置管理中,使用单例模式可以确保只有一个配置管理实例,方便全局访问配置信息。

class ConfigurationManager {constructor() {if (!ConfigurationManager.instance) {this.config = { /* 配置信息 */ };ConfigurationManager.instance = this;}return ConfigurationManager.instance;}getConfig(key) {return this.config[key];}
}const configManager = new ConfigurationManager();
console.log(configManager.getConfig('apiUrl')); // 输出: 配置信息中的 apiUrl

单例模式的进阶应用

1. 日志记录器

在应用中使用单例模式创建一个全局的日志记录器,确保只有一个实例记录所有日志信息。

class Logger {constructor() {if (!Logger.instance) {this.logs = [];Logger.instance = this;}return Logger.instance;}log(message) {this.logs.push(message);console.log(message);}printLogs() {console.log('All logs:');this.logs.forEach(log => console.log(log));}
}const logger = new Logger();
logger.log('Log message 1');
logger.log('Log message 2');const anotherLogger = new Logger();
console.log(logger === anotherLogger); // 输出: true
anotherLogger.printLogs(); // 输出: Log message 1 \n Log message 2

在这个例子中,Logger 类用于记录应用中的日志信息,通过单例模式确保只有一个全局的日志记录器。

2. 文件系统管理

在需要管理文件系统的应用中,使用单例模式可以确保只有一个实例负责文件系统的操作,避免文件冲突和资源竞争。

class FileSystemManager {constructor() {if (!FileSystemManager.instance) {this.files = [];FileSystemManager.instance = this;}return FileSystemManager.instance;}createFile(name) {this.files.push(name);console.log(`File '${name}' created.`);}listFiles() {console.log('Files in the system:');this.files.forEach(file => console.log(file));}
}const fileSystem = new FileSystemManager();
fileSystem.createFile('document.txt');
fileSystem.createFile('image.jpg');const anotherFileSystem = new FileSystemManager();
console.log(fileSystem === anotherFileSystem); // 输出: true
anotherFileSystem.listFiles(); // 输出: document.txt \n image.jpg

在这个例子中,FileSystemManager 类用于管理文件系统,确保只有一个实例负责文件的创建和列举。

3. 数据库连接

在需要管理数据库连接的应用中,使用单例模式可以确保只有一个实例负责数据库的连接,提高性能和资源利用率。

class DatabaseConnection {constructor() {if (!DatabaseConnection.instance) {this.isConnected = false;DatabaseConnection.instance = this;}return DatabaseConnection.instance;}connect() {if (!this.isConnected) {console.log('Database connected.');this.isConnected = true;} else {console.log('Already connected to the database.');}}disconnect() {if (this.isConnected) {console.log('Database disconnected.');this.isConnected = false;} else {console.log('Not connected to the database.');}}
}const dbConnection = new DatabaseConnection();
dbConnection.connect();
dbConnection.disconnect();const anotherDbConnection = new DatabaseConnection();
console.log(dbConnection === anotherDbConnection); // 输出: true
anotherDbConnection.connect(); // 输出: Already connected to the database.

在这个例子中,DatabaseConnection 类用于管理数据库连接,确保只有一个实例负责数据库的连接和断开。

单例模式的性能考虑

尽管单例模式确保只有一个实例存在,但在大型应用中,可能会导致全局状态的集中管理,增加了代码的耦合性。此外,在多线程环境中,需要考虑线程安全性,避免因为竞态条件而导致的问题。

在性能要求较高的场景,可以根据具体需求选择使用懒汉式或饿汉式单例模式。懒汉式能够延迟实例的创建,降低了启动时的负载,但在首次访问时可能会有性能开销。饿汉式则在应用启动时立即创建实例,保证了全局的唯一性,但可能增加了启动时间。

总结

JavaScript 单例模式是一种有力的设计模式,旨在确保一个类仅有一个实例,并提供一个全局访问点。通过懒汉式、饿汉式和模块模式等多种实现方式,开发者可以根据具体场景选择适合的单例模式,使得代码更为灵活和可维护。

在懒汉式中,实例在首次访问时被创建,延迟加载有助于降低启动时的负载。而饿汉式在应用启动时即创建实例,保证了全局唯一性,但可能增加了启动时间。模块模式结合了闭包和IIFE,为单例提供了一种更为模块化和安全的实现方式。

单例模式在实际应用中有着广泛的应用,包括管理全局状态、数据缓存、配置管理等方面。通过确保唯一实例的存在,单例模式提高了代码的可维护性和可读性,使得应用在全局范围内具备更好的控制和管理能力。

然而,开发者在使用单例模式时需要注意全局状态的管理可能带来的代码耦合问题。在性能要求较高的场景,可以选择懒汉式或饿汉式单例,根据具体需求权衡延迟加载和启动时间的取舍。综合而言,JavaScript 单例模式为项目提供了更好的架构和代码组织方式,让代码充满设计模式的智慧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/183217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

矩阵代数与MATLAB实现(特征值、广义特征值、酋矩阵、)

矩阵代数的相关知识 目录 一、特征值与特征向量 1、特征值与特征向量 2、MATLAB计算 二、广义特征值与广义特征向量 1、广义特征值与广义特征向量 2、MATLAB计算 三、酋矩阵 1、酋矩阵 2、MATLAB计算 四、未完待续 总结 提示:以下是本篇文章正文内容&…

Pytorch从零开始实战11

Pytorch从零开始实战——ResNet-50V2算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNet-50V2算法实战环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook,使用Python3.8,Pyt…

VUE语法-ref和reactive响应式数据引用

1、响应式概述 在vue中定义一个参数,当这个参数在使用中发生了变化,在页面中对这个数据应用的地方都会同步的发生变化,这个就是数据响应式。 2、创建一个非响应式的参数 该程序中采用的是VUE3的用法: 1、在程序中定义了一个局…

GraphCast:基于机器学习的全球中期天气预测模型

文章信息 文章题为”GraphCast: Learning skillful medium-range global weather forecasting”,该文章于2023年发表至Science,文章内容主要关于利用机器学习模型,实现高效、准确的全球中期天气预测。由于文章内容较多,本文仅对研…

力扣刷题篇之分治

系列文章目录 目录 系列文章目录 前言 一、分解问题 二、解决子问题 三、合并结果 总结 前言 刷题按照: [力扣刷题攻略] Re:从零开始的力扣刷题生活 - 力扣(LeetCode) 参考: 「五大常用算法」一文搞懂分治算法…

大数据HCIE成神之路之数学(4)——最优化实验

最优化实验 1.1 最小二乘法实现1.1.1 算法介绍1.1.2 代码实现1.2 梯度下降法实现1.2.1 算法介绍1.2.2 代码实现1.3 拉格朗日乘子法1.3.1 实验1.3.2 实验操作步骤1.1 最小二乘法实现 1.1.1 算法介绍 最小二乘法(Least Square Method),做为分类回归算法的基础,有着悠久的历…

第20章:多线程

20.1 线程简介 在Java中,并发机制非常重要,程序员可以在程序中执行多个线程,每个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程。但是,并不是所有编程语言都支持多线程。 线程的特点&#…

visual studio 2022 更改字体和大小

工具--->选项 文本编辑器 输出窗口

Linux系统之uptime命令的基本使用

Linux系统之uptime命令的基本使用 一、uptime介绍二、uptime命令使用帮助2.1 uptime的help帮助信息2.2 uptime的语法解释 三、uptime的基本使用3.1 直接使用uptime命令3.2 显示uptime版本信息3.3 显示系统运行时间3.4 显示系统最后一次启动时间 四、uptime命令的使用注意事项 一…

基于YOLOv8深度学习的生活垃圾分类目标检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

C++前缀和算法的应用:优化了6版的1324模式

本文涉及的基础知识点 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 本题其它解法 C前缀和算法的应用:统计上升四元组 类似题解法 包括题目及代码C二分查找算法:132 模式解法一枚举3C二分查找算法:…

k8s中Pod控制器简介,ReplicaSet、Deployment、HPA三种处理无状态pod应用的控制器介绍

目录 一.Pod控制器简介 二.ReplicaSet(简写rs) 1.简介 (1)主要功能 (2)rs较完整参数解释 2.创建和删除 (1)创建 (2)删除 3.扩容和缩容 &#xff08…

vuepress-----7、发布在GitHub

# 7、发布在GitHub 在你的项目中,创建一个如下的 deploy.sh 文件(请自行判断去掉高亮行的注释): #!/usr/bin/env sh# 确保脚本抛出遇到的错误 set -e# 生成静态文件 npm run docs:build# 进入生成的文件夹 cd docs/.vuepress/dist# 如果是发…

WebUI自动化学习(Selenium+Python+Pytest框架)004

接下来,WebUI基础知识最后一篇。 1.下拉框操作 关于下拉框的处理有两种方式 (1)按普通元素定位 安装普通元素的定位方式来定位下拉框,使用元素的操作方法element.click()方法来操作下拉框内容的选择 (2&#xff09…

PCB设计注意事项

四个二极管不能省略 pwm波跟电机频率不要是倍频 运放越靠近取样电阻越好 反向输入端跟输出端很敏感,有寄生电容就容易震荡 距离取样电阻近就会距离单片机远,那么线上会有寄生电容,这时候在输出端接一个10k电阻到地

深度学习-模型调试经验总结

1、 这句话的意思是:期望张量的后端处理是在cpu上,但是实际是在cuda上。排查代码发现,数据还在cpu上,但是模型已经转到cuda上,所以可以通过把数据转到cuda上解决。 解决代码: tensor.to("cuda")…

Redis 入门和环境搭建

认识Redis Redis是一种NoSQL数据库,以键值对形式存储数据,支持多种数据结构,包括字符串、哈希、列表、集合、有序集合等,使其适用于多种应用场景。由于所有数据都存储在内存中,Redis的读写性能非常高。同时&#xff0…

安网AC智能路由系统actpt_5g.data敏感信息泄露漏洞复现 [附POC]

文章目录 安网AC智能路由系统actpt_5g.data敏感信息泄露漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 安网AC智能路由系统actpt_5g.data敏感信息泄露漏洞复现 [附POC] 0x01 前言 免责声明:请勿利…

面试:说一下深拷贝,浅拷贝,引用拷贝吧;Object类中的clone是哪种呢?

目录 深拷贝、浅拷贝、引用拷贝Object类的clone()方法 深拷贝、浅拷贝、引用拷贝 ● 浅拷贝: 对基本数据类型进行值传递; 对引用类型,复制了一份引用类型的变量 里面存储的内存地址一样 指向的对象也一样。 ● 深拷贝:对基本数据…

kettle入门教程

一、概述 1.什么是kettle Kettle是一款开源的ETL(Extract-Transform-Load)工具,纯java编写,可以在Window、Linux、Unix上运行,绿色无需安装,数据抽取高效稳定。 2.kettle工程存储方式 (1)以XML形式存储 …