当前位置: 首页 > news >正文

JavaScript单例模式

JavaScript单例模式

  • 1 什么是单例模式
  • 2 实现一个基础的单例模式
  • 3 透明的单例模式
  • 4 用代理实现单例模式
  • 5 JavaScript 中的单例模式
  • 6 惰性单例

1 什么是单例模式

保证一个类只有一个实例,并提供一个访问它的全局访问点,这就是单例模式。

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如window对象、全局缓存等。

2 实现一个基础的单例模式

根据单例模式的特点,在实现单例模式时,我们要保证某个类只能创建一个实例对象,那么实现的基本思路就是:用一个变量标识当前是都已经为某个类创建过对象,如果是,在下一次获取该类的实例时,直接返回之前创建的对象,否则创建一个新对象,示例代码如下:

// 定义一个构造函数MyExample,定义属性name与instance
function MyExample(name) {this.name = name;this.instance = null;
}
// 在原型上定义getName方法
MyExample.prototype.getName = function () {console.log(this.name);
};
// 为构造函数定义getInstance方法,用来获取类的实例
MyExample.getInstance = function (name) {// 标识是否创建了实例,如果没有,赋值为新的实例,如果已经创建,返回原来的实例if (!this.instance) {this.instance = new MyExample(name);}return this.instance;
};// 为MyExample类创建实例,看似创建两个实例,实际上都是同一个实例
var e1 = MyExample.getInstance("example1");
var e2 = MyExample.getInstance("example2");console.log(e1 === e2); // true

我们通过MyExample.getInstance来获取 MyExample类的唯一对象,这种方式相对简单,但有一个问题,就是增加了这个类的“不透明性”,MyExample类的使用者必须知道这是一个单例类,跟以往通过new XXX的方式来获取对象不同。

3 透明的单例模式

在上一步中,由于该类的“不透明性”,用户在使用时会有一些困难,因此在本节中实现一个“透明”的单例类,让用户在使用这个类创建对象时,可以和使用其他普通类一样。

接下来实现一个单例类CreateDiv,这个类的作用是在页面创建唯一的div节点,代码如下:

var CreateDiv = (function () {var instance; // 标识是否创建过实例// 创建CreateDiv类var CreateDiv = function (html) {// 如果已经创建过实例,返回当前实例if (instance) {return instance;}// 如果没有创建实例。创建一个div元素,并返回this.init();this.html = html;return (instance = this);};// 定义init方法,目的是创建一个div元素,元素内容由我们自己定义CreateDiv.prototype.init = function () {var div = document.createElement("div");div.innerHTML = this.html;document.body.appendChild(div);};return CreateDiv;
})();var e1 = new CreateDiv("example1");
var e2 = new CreateDiv("example2");console.log(e1 === e2); // true

虽然现在完成了一个透明的单例类的编写,但它同样有一些缺点,为了把instance封装起来,使用了自执行的匿名函数和闭包,并且让这个匿名函数返回真正的构造方法,复杂度高,可读性也变差了。

4 用代理实现单例模式

在上面的例子中,假设我们某天需要利用这个类,在页面中创建千千万万的div,即要让这个类从单例类变成一个普通的可产生多个实例的类,那我们必须得改写CreateDiv构造函数,这种修改会给我们带来不必要的烦恼,因此我们通过引入代理类的方式来解决这个问题

首先在CreateDiv构造函数中,把负责管理单例的代码提出来,使它成为一个普通的创建div的类:

var CreateDiv = function (html) {this.html = html;this.init();
};CreateDiv.prototype.init = function () {var div = document.createElement("div");div.innerHTML = this.html;document.body.appendChild(div);
};

接下来引入代理类proxySingletonCreateDiv

var ProxySingletonCreateDiv = (function () {var instance;return function (html) {if (!instance) {instance = new CreateDiv(html);}return instance;};
})();var e1 = new ProxySingletonCreateDiv("example1");
var e2 = new ProxySingletonCreateDiv("example2");console.log(e1 === e2); // true

上面的例子通过引入代理类的方式完成了一个单例模式的改写,与之前不同的是,现在把负责管理单例的逻辑移到了代理类proxySingletonCreateDiv中。这样一来,CreateDiv就变成了一个普通的类,它跟 proxySingletonCreateDiv组合起来可以达到单例模式的效果。

5 JavaScript 中的单例模式

前面提到的几种单例模式的实现,更多的是接近传统面向对象语言中的实现,单例对象从“类”中创建而来,在以类为中心的语言中,这是很自然的做法。比如在Java中,如果需要某个对象,就必须先定义一个类,对象总是从类中创建而来的。

JavaScript其实是一门无类语言,创建对象的方法非常简单,既然我们只需要一个“唯一”的对象,为什么要为它先创建一个“类”呢,传统的单例模式实现在JavaScript中并不适用。

单例模式的核心是确保只有一个实例,并提供全局访问。

全局变量不是单例模式,但在JavaScript开发中,我们经常会把全局变量当成单例来使用。例如:

var a = {}; 

当用这种方式创建对象a时,对象a确实是独一无二的。如果a变量被声明在全局作用域下,我们可以在代码中的任何位置使用这个变量,这样就满足了单例模式的两个条件。但是全局变量存在很多问题,它很容易造成命名空间污染。

我们可以采用以下几种方式降低全局变量带来的命名污染:

1、使用命名空间,适当地使用命名空间,并不会杜绝全局变量,但可以减少全局变量的数量,最简单的方法依然是用对象字面量的方式:

var namespace1 = {a: function () {alert(1);},b: function () {alert(2);},
};

2、使用闭包封装私有变量,这种方法把一些变量封装在闭包的内部,只暴露一些接口跟外界通信:

var user = (function () {var __name = "sven",__age = 29;return {getUserInfo: function () {return __name + "-" + __age;},};
})();

我们用下划线来约定私有变量__name__age,它们被封装在闭包产生的作用域中,外部是访问不到这两个变量的,这就避免了对全局的命令污染。

6 惰性单例

惰性单例指的是在需要的时候才创建对象实例。

惰性单例是单例模式的重点,实例对象instance总是在我们调用MyExample.getInstance的时候才被创建,而不是在页面加载好的时候就创建,示例代码如下:

MyExample.getInstance = (function () {var instance = null;return function (name) {if (!instance) {instance = new MyExample(name);}return instance;};
})();

相关文章:

JavaScript单例模式

JavaScript单例模式 1 什么是单例模式2 实现一个基础的单例模式3 透明的单例模式4 用代理实现单例模式5 JavaScript 中的单例模式6 惰性单例 1 什么是单例模式 保证一个类只有一个实例,并提供一个访问它的全局访问点,这就是单例模式。 单例模式是一种常…...

centos下安装jenkins.war

https://get.jenkins.io/war-stable/ 下载jenkins.war包,(2.164.1 版本支持1.8,其他的都是jdk11),可以安装完成后更新jenkins.war的安装包启动jenkins命令 java -jar jenkins.war --httpPort8010访问http://IP:8010/jenkins (密码在/root/.jenkins/secre…...

App线上网络问题优化策略

在我们App开发过程中,网络是必不可少的,几乎很难想到有哪些app是不需要网络传输的,所以网络问题一般都是线下难以复现,一旦到了用户手里就会碰到很多疑难杂症,所以对于网络的监控是必不可少的,针对用户常见…...

PDF 工具箱

PDF 工具箱 V9.0.0.1 程序:VB.net 运行库:NET Framework 4.5 功能简介: 1、PDF文件多文件合并,可调整顺序。 2、PDF文件拆分,将每页拆分成独立的PDF文件。 3、PDF文件添加水印,文字或图片水印&…...

大数据组件系列-Hadoop每日小问

1、谈谈对HDFS的理解?HDFS这种存储适合哪些场景? HDFS即Hadoop Distributed File System,Hadoop 分布式文件系统。它为的是解决海量数据的存储与分析的问题,它本身是源于Google在大数据方面的论文,GFS-->HDFS; HD…...

【前端】在Vue页面中引入其它vue页面 数据传输 相互调用方法等

主页面 home 从页面 headView 需求 在 home.vue 中引用 headView.Vue 方案: home.vue 代码: 只需要在home.vue 想要的地方添加 <headView></headView> <script>//聊天页面 import headView /view/headView.vueexport default {components: {headView},…...

网络通信深入解析:探索TCP/IP模型

http协议访问web 你知道在我们的网页浏览器的地址当中输入url&#xff0c;未必是如何呈现的吗&#xff1f; web浏览器根据地址栏中指定的url&#xff0c;从web服务器获取文件资源&#xff08;resource&#xff09;等信息&#xff0c;从而显示出web页面。web使用HTTP&#xff08…...

可靠的可视化监控平台应用在那些场景?

可视化监控平台是一种用户友好的工具&#xff0c;可以帮助用户实时监控IT设备的运行状态和网络流量&#xff0c;以及监测安全性和性能指标。它们通常采用图形化界面&#xff0c;使得用户能够直观地了解设备和网络的状态。 以下是一些可视化监控平台常见的应用场景&#xff1a;…...

从 BBR 失速到带宽探测

看一下 pacing 流失速的成因&#xff1a; 一段时间收不到 ack&#xff0c;丢了 ack 自时钟&#xff0c;cwnd 将耗尽&#xff0c;bbr 虽有 cwnd_gain(上图没有表现)&#xff0c;但在该 cwnd_gain 下不依赖 ack 持续坚持发送多久取决于 cwnd_gain 的数值。 bbr 失速的后果在于…...

MobaXterm使用sz/rz命令下载上传文件

MobaXterm使用sz/rz命令下载上传文件 1 参考文档2 下载3 上传 1 参考文档 MobaXterm使用sz/rz命令下载上传文件 2 下载 步骤1&#xff1a;sz filename 步骤2&#xff1a;ctrl 鼠标右键 步骤3&#xff1a;Receive file using Z-modem 3 上传 步骤1&#xff1a;rz 步骤2&am…...

vue el-popover hover延时触发,el-popover 鼠标放上三秒以后触发

背景&#xff1a;el-popover hover只要鼠标刮过就显示 多个el-popover出现加载卡顿 解决方案 给el-popover加一个延时显示 <template><div><el-popovertrigger"hover":open-delay"3000"content"这是一个Popover"><button…...

计算机竞赛 基于深度学习的人脸识别系统

前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的人脸识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/…...

Android扫码连接WIFI实现

0&#xff0c;目标 APP中实现扫WIFI分享码自动连接WIFI功能 1&#xff0c;前提条件 设备需要有个扫码器&#xff08;摄像头拍照识别也行&#xff09;&#xff0c;APP调用扫码器读取WIFI连接分享码。 2&#xff0c;增加权限 在AndroidManifest.xml中增加权限 <uses-permissi…...

TrOCR – 基于 Transformer 的 OCR 入门指南

多年来,光学字符识别 (OCR) 出现了多项创新。它对零售、医疗保健、银行和许多其他行业的影响是巨大的。尽管有着悠久的历史和多种最先进的模型,研究人员仍在不断创新。与深度学习的许多其他领域一样,OCR 也看到了变压器神经网络的重要性和影响。如今,我们拥有像TrOCR(Tran…...

MAC终端美化

先看看效果&#xff1a; 1.安装on-my-zsh 打开终端&#xff0c;输出&#xff1a; sh -c "$(curl -fsSL https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh)"安装过程中如果出现了链接超时的错误&#xff0c;不要慌&#xff0c;就再来一次&#x…...

Matlab常用字符串操作教程

Matlab是一种功能强大的编程语言&#xff0c;它提供了丰富的字符串操作函数。在本教程中&#xff0c;我们将介绍一些常用的Matlab字符串操作函数和用法。 字符串的创建和访问&#xff1a; 使用单引号或双引号创建字符串&#xff1a;str Hello World; 或 str "Hello Worl…...

基于SSM的汽车养护管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

Redis发布订阅机制学习

【IT老齐151】Redis发布订阅机制是如何实现的&#xff1f;_哔哩哔哩_bilibili go-redis的发布与订阅 - 知乎 (zhihu.com) 前置&#xff1a; 先输入 redis-server.exe 启动redis&#xff0c;否则对应接口不开放 再输入 redis-cli 命令启动客户端服务 1.机制示意图 当一…...

施展世界:GPT时代需要的教育,是学会如何提出好问题

来源&#xff1a;BV1co4y1W7h7 有很多脑力活&#xff0c;它实际上是伪装成脑力活的体力活&#xff0c;它在回答问题这个层面&#xff0c;那是非常的厉害&#xff0c;人现在肯定是比不过它了&#xff0c;注意了&#xff0c;这是回答问题的层面&#xff0c;但问题是谁来问问题呢&…...

Excel学习 WPS版

Excel学习 1.界面基础1.1 方格移动快捷键1.2 自动适配文字长度1.3 跨栏置中1.4 多个单元格同宽度&#xff1a;1.5 下拉框选择1.6 打印预览1.7 绘制边框1.8 冻结一行多行表头1.9 分割视图 2.日期相关2.1 今日日期快捷键2.2 月份提取 3.数学公式3.1 自动增长3.2 排序3.3 筛选3.4 …...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...

电脑定时关机工具推荐

软件介绍 本文介绍一款轻量级的电脑自动关机工具&#xff0c;无需安装&#xff0c;使用简单&#xff0c;可满足定时关机需求。 工具简介 这款关机助手是一款无需安装的小型软件&#xff0c;文件体积仅60KB&#xff0c;下载后可直接运行&#xff0c;无需复杂配置。 使用…...