JavaScript 中的单例模式

news2025/4/23 15:27:03

单例模式在 JavaScript 中是一种确保类只有一个实例,并提供全局访问点的方式。由于 JavaScript 的语言特性(如对象字面量、模块系统等),实现单例有多种方式。

常见实现方式

1. 对象字面量(最简单的单例)

const singleton = {
  property: "value",
  method: function() {
    console.log("I am a method");
  }
};

// 使用
singleton.method();

特点

  • 对象字面量本身就是单例

  • 无法延迟初始化

  • 不能私有化成员

2. 闭包实现(带私有成员)

const Singleton = (function() {
  // 私有变量
  let instance;
  
  function init() {
    // 私有方法和属性
    const privateVar = "I am private";
    const privateRandom = Math.random();
    
    return {
      // 公共方法
      publicMethod: function() {
        console.log("Public can see me");
      },
      // 公共属性
      publicProperty: "I am public",
      // 访问私有变量的方法
      getPrivateVar: function() {
        return privateVar;
      },
      getRandomNumber: function() {
        return privateRandom;
      }
    };
  }
  
  return {
    getInstance: function() {
      if (!instance) {
        instance = init();
      }
      return instance;
    }
  };
})();

// 使用
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // true
console.log(instance1.getRandomNumber() === instance2.getRandomNumber()); // true

特点

  • 真正的单例实现

  • 可以包含私有成员

  • 延迟初始化

  • 线程安全(JS是单线程)

3. ES6 Class 实现

class Singleton {
  constructor() {
    if (!Singleton.instance) {
      this._data = [];
      Singleton.instance = this;
    }
    return Singleton.instance;
  }
  
  add(item) {
    this._data.push(item);
  }
  
  get(id) {
    return this._data.find(item => item.id === id);
  }
}

// 使用
const instance1 = new Singleton();
const instance2 = new Singleton();

instance1.add({ id: 1, name: "test" });
console.log(instance2.get(1)); // { id: 1, name: "test" }
console.log(instance1 === instance2); // true

4. 模块模式(现代JS常用方式)

// singleton.js
let instance = null;
let data = []; // 私有变量

export default class Singleton {
  constructor() {
    if (!instance) {
      instance = this;
    }
    return instance;
  }
  
  add(item) {
    data.push(item);
  }
  
  get(id) {
    return data.find(item => item.id === id);
  }
  
  getAll() {
    return [...data];
  }
}

// 使用
import Singleton from './singleton.js';

const instance1 = new Singleton();
const instance2 = new Singleton();

instance1.add({ id: 1, name: "Item 1" });
console.log(instance2.getAll()); // [{ id: 1, name: "Item 1" }]

实际应用场景

  1. 全局状态管理

    // 类似Redux的store就是单例
    const store = {
      state: { count: 0 },
      increment() {
        this.state.count++;
      }
    };
  2. 对话框/模态框管理

    const Modal = (function() {
      let instance;
      
      function createModal() {
        const modal = document.createElement('div');
        // 初始化模态框...
        return {
          open: () => modal.style.display = 'block',
          close: () => modal.style.display = 'none'
        };
      }
      
      return {
        getInstance: function() {
          if (!instance) {
            instance = createModal();
          }
          return instance;
        }
      };
    })();
  3. 缓存系统

    const Cache = {
      data: {},
      set(key, value) {
        this.data[key] = value;
      },
      get(key) {
        return this.data[key];
      },
      clear() {
        this.data = {};
      }
    };

注意事项

  1. 模块系统本身就是单例:在现代JavaScript中,ES6模块默认就是单例

    // logger.js
    export default {
      log(message) {
        console.log(message);
      }
    }
    
    // 无论多少次import,得到的都是同一个对象
  2. 测试困难:单例可能导致测试困难,因为状态是共享的

  3. 全局污染:过度使用单例可能导致命名冲突和难以追踪的依赖关系

  4. Node.js中的单例:在Node.js中,模块缓存确保require多次返回同一个实例

JavaScript中的单例模式相比传统面向对象语言更灵活,可以根据具体需求选择适合的实现方式。

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

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

相关文章

影刀填写输入框(web) 时出错: Can not convert Array to String

环境: 影刀5.26.24 Win10专业版 问题描述: [错误来源]行12: 填写输入框(web) 执行 填写输入框(web) 时出错: Can not convert Array to String. 解决方案: 1. 检查变量内容 在填写输入框之前,打印BT和NR变量的值&#xff…

词语关系图谱模型

参数配置说明 sentences, # 分词后的语料(列表嵌套列表) vector_size100, # 每个词的向量维度 window5, # 词与上下文之间的最大距离(滑动窗口大小) min_count5, # 忽略出现次数小于5的…

HTTP的请求消息Request和响应消息Response

一:介绍 (1)定义 service方法里的两个参数 (2)过程 Request:获取请求数据 浏览器发送http请求数据(字符串),字符串被tomcat解析,解析后tomcat会将请求数据放入request对象 Response:…

C++异步操作 - future async package_task promise

异步 异步编程是一种程序设计范式,​​允许任务在等待耗时操作(如I/O、网络请求)时暂停执行,转而处理其他任务,待操作完成后自动恢复​​。其核心目标是​​避免阻塞主线程​​,提升程序的并发性和响应速度…

数据结构——栈以及相应的操作

栈(Stack) 在维基百科中是这样定义的: 堆栈(stack) 又称为栈或堆叠,是计算机科学中的一种抽象资料类型,只允许在有序的线性资料集合中的一端(称为堆栈顶端,top)进行加入数据(push)和…

如何应对政策变化导致的项目风险

应对政策变化导致的项目风险,核心在于:加强政策研判机制、建立动态应对流程、构建合规应急预案、强化跨部门联动、提升项目柔性与调整能力。其中,加强政策研判机制 是所有防范工作中的“前哨哨兵”,可以让项目团队在政策风向转变之…

ASP.Net Web Api如何更改URL

1.找到appsettings.json 修改如下: 主要为urls的修改填本机私有地址即可 {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": &q…

【HTTPS协议原理】数据加密、如何防止中间人攻击、证书和签名、HTTPS完整工作流程

⭐️个人主页:小羊 ⭐️所属专栏:Linux网络 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 数据加密常见的加密方式数据摘要方案一:仅使用对称加密方案二:仅使用非对称加密方案三:双…

Java中链表的深入了解及实现

一、链表 1.链表的概念 1.1链表是⼀种物理存储结构上⾮连续存储结构,数据元素的逻辑顺序是通过链表中的引⽤链接次序实现的 实际中链表的结构⾮常多样,以下情况组合起来就有8种链表结构: 2.链表的实现 1.⽆头单向⾮循环链表实现 链表中的…

植物大战僵尸杂交版v3.6最新版本(附下载链接)

B站游戏作者潜艇伟伟迷于4月19日更新了植物大战僵尸杂交版3.6版本!!!,有b站账户的记得要给作者三连关注一下呀! 不多废话下载链接放上: 夸克网盘链接::https://pan.quark.cn/s/1af9b…

【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 📚欢迎订阅专栏…

背包问题模板

文章目录 01背包题意思路代码优化 完全背包题意思路代码优化 多重背包题意思路代码优化 分组背包题意思路代码 01背包 特点:每件物品最多只能用一次 01背包问题 题意 给出每件物品的体积v,价值w,求解能装入背包的的物品的最大价值,并且每件物品只能选一…

Sentinel源码—8.限流算法和设计模式总结二

大纲 1.关于限流的概述 2.高并发下的四大限流算法原理及实现 3.Sentinel使用的设计模式总结 3.Sentinel使用的设计模式总结 (1)责任链模式 (2)监听器模式 (3)适配器模式 (4)模版方法模式 (5)策略模式 (6)观察者模式 (1)责任链模式 一.责任链接口ProcessorSlot 二.责…

VulnHub-DarkHole_1靶机渗透教程

VulnHub-DarkHole_1靶机渗透教程 1.靶机部署 [Onepanda] Mik1ysomething 靶机下载:https://download.vulnhub.com/darkhole/DarkHole.zip 直接使用VMware打开就行 导入成功,打开虚拟机,到此虚拟机部署完成! 注意&#xff1a…

边缘计算全透视:架构、应用与未来图景

边缘计算全透视:架构、应用与未来图景 一、产生背景二、本质三、特点(一)位置靠近数据源(二)分布式架构(三)实时性要求高 四、关键技术(一)硬件技术(二&#…

MQ底层原理

RabbitMQ 概述 RabbitMQ 是⼀个开源的⾼性能、可扩展、消息中间件(Message Broker),实现了 Advanced Message Queuing Protocol(AMQP)协议,可以帮助不同应⽤程序之间进⾏通信和数据交换。RabbitMQ 是由 E…

本地部署DeepSeek-R1模型接入PyCharm

以下是DeepSeek-R1本地部署及接入PyCharm的详细步骤指南,整合了视频内容及官方文档核心要点: 一、本地部署DeepSeek-R1模型 1. 安装Ollama框架 ​下载安装包 访问Ollama官网(https://ollama.com/download)Windows用户选择.exe文件,macOS用户选择.dmg包。 ​安装验证 双击…

Java基于SpringBoot的企业车辆管理系统,附源码+文档说明

博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…

进阶篇 第 2 篇:自相关性深度解析 - ACF 与 PACF 图完全指南

进阶篇 第 2 篇:自相关性深度解析 - ACF 与 PACF 图完全指南 (图片来源: Negative Space on Pexels) 欢迎来到进阶系列的第二篇!在上一篇,我们探讨了更高级的时间序列分解技术和强大的指数平滑 (ETS) 预测模型。ETS 模型通过巧妙的加权平均捕…

鸿蒙移动应用开发--渲染控制实验

任务:使用“对象数组”、“ForEach渲染”、“Badge角标组件”、“Grid布局”等相关知识,实现生效抽奖卡案例。如图1所示: 图1 生肖抽奖卡实例图 图1(a)中有6张生肖卡可以抽奖,每抽中一张,会通过弹层显示出来&#xf…