js设计模式【详解】—— 单例模式

简介: js设计模式【详解】—— 单例模式

单例模式的定义

单例模式:一个类只能有一个实例,即使多次实例化该类,也只返回第一次实例化后的实例对象。

核心要点:确保只有一个实例, 并提供全局访问。

推荐使用场景:用单例模式进行命名空间,管理模块

优点:

1. 减少不必要的内存开销

2. 减少全局的函数和变量冲突

演示范例——通过对象字面量创建对象的方式实现单例模式

得益于JavaScript创建对象的方式十分灵活, 可以直接通过对象字面量的方式实例化一个对象, 而其他面向对象的语言必须使用类进行实例化,所以下方代码中定义的对象timeTool就已经是一个单例模式创建对象的实例(letconst不允许重复声明的特性,确保了timeTool不能被重新覆盖)

let timeTool = {
  name: '处理时间工具库',
  getISODate: function() {},
  getUTCDate: function() {}
}

演示范例——通过定义类实现单例模式

class SingletonApple {
  constructor(name, creator, products) {
      this.name = name;
      this.creator = creator;
      this.products = products;
  }
  //静态方法
  static getInstance(name, creator, products) {
    if(!this.instance) {
      this.instance = new SingletonApple(name, creator, products);
    }
    return this.instance;
  }
}
 
let appleCompany = SingletonApple.getInstance('苹果公司', '乔布斯', ['iPhone', 'iMac', 'iPad', 'iPod']);
let copyApple = SingletonApple.getInstance('苹果公司', '阿辉', ['iPhone', 'iMac', 'iPad', 'iPod'])
 
console.log(appleCompany === copyApple); //true

通过类的静态方法getInstance创建实例,若是第一次创建对象实例则new一个对象实例(触发构造函数constructor),若检测到已进行过实例化,则返回已创建过的对象实例,不再重新创建实例。

应用场景——命名空间

命名空间:全局只暴露一个对象名,将变量作为该对象的属性,将方法作为该对象的方法,这样就能大大减少全局变量的个数,用来解决全局变量冲突的问题

//开发者A写了一大段js代码
let devA = {
  addNumber() { }
}
 
//开发者B开始写js代码
let devB = {
  add: ''
}
 
//A重新维护该js代码
devA.addNumber();

devAdevB就是两个命名空间,采用命名空间可以有效减少全局变量的数量,以此解决变量冲突的发生。

应用场景——管理模块

var devA = (function(){
  //ajax模块
  var ajax = {
    get: function(api, obj) {console.log('ajax get调用')},
    post: function(api, obj) {}
  }
 
  //dom模块
  var dom = {
    get: function() {},
    create: function() {}
  }
  
  //event模块
  var event = {
    add: function() {},
    remove: function() {}
  }
 
  return {
    ajax: ajax,
    dom: dom,
    event: event
  }
})()

上面的代码库中有ajax,domevent三个模块,用同一个命名空间devA来管理。在进行相应操作的时候,只需要devA.ajax.get()进行调用即可,这样可以让库的功能更加清晰。

项目实战范例——单例模式

范例功能:点击登录按钮后永远只返回一个登录框的实例。

实现思路:

  1. 给顶部导航模块的登录按钮注册点击事件
  2. 登录按钮点击后JS动态创建遮罩层和登陆弹框
  3. 遮罩层和登陆弹框插入到页面中
  4. 给登陆框中的关闭按钮注册事件, 用于关闭遮罩层和弹框

……

代码解析:

第一次点击登录按钮时,调用Login.getInstance()实例化了一个登录框,在之后的点击中,不再重新创建新的登录框,只是移除掉"display: none"这个样式来显示登录框,节省了内存开销。

1. 给页面添加顶部导航栏的HTML代码

  <nav class="top-bar">
    <div class="top-bar_left">
      LTH BLOG
    </div>
    <div class="top-bar_right">
      <div class="login-btn">登录</div>
      <div class="signin-btn">注册</div>
    </div>
  </nav>

2. 使用ES6的语法创建Login类

class Login {
 
  //构造器
  constructor() {
    this.init();
  }
 
  //初始化方法
  init() {
    //新建div
    let mask = document.createElement('div');
    //添加样式
    mask.classList.add('mask-layer');
    //添加模板字符串
    mask.innerHTML = 
    `
    <div class="login-wrapper">
      <div class="login-title">
        <div class="title-text">登录框</div>
        <div class="close-btn">×</div>
      </div>
      <div class="username-input user-input">
        <span class="login-text">用户名:</span>
        <input type="text">
      </div>
      <div class="pwd-input user-input">
        <span class="login-text">密码:</span>
        <input type="password">
      </div>
      <div class="btn-wrapper">
        <button class="confrim-btn">确定</button>
        <button class="clear-btn">清空</button>
      </div>
    </div>
    `;
    //插入元素
    document.body.insertBefore(mask, document.body.childNodes[0]);
 
    //注册关闭登录框事件
    Login.addCloseLoginEvent();
  }
 
  //静态方法: 获取元素
  static getLoginDom(cls) {
    return  document.querySelector(cls);
  }
 
  //静态方法: 注册关闭登录框事件
  static addCloseLoginEvent() {
    this.getLoginDom('.close-btn').addEventListener('click', () => {
      //给遮罩层添加style, 用于隐藏遮罩层
      this.getLoginDom('.mask-layer').style = "display: none";
    })
  }
 
  //静态方法: 获取实例(单例)
  static getInstance() {
    if(!this.instance) {
      this.instance = new Login();
    } else {
      //移除遮罩层style, 用于显示遮罩层
      this.getLoginDom('.mask-layer').removeAttribute('style');
    }
    return this.instance;
  }
}

3. 给登录按钮添加注册点击事件

//注册点击事件
Login.getLoginDom('.login-btn').addEventListener('click', () => {
  Login.getInstance();
})

更多设计模式详见——js设计模式【详解】总目录

https://blog.csdn.net/weixin_41192489/article/details/116154815

目录
相关文章
|
26天前
|
设计模式 存储 前端开发
前端必须掌握的设计模式——单例模式
单例模式是一种简单的创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。适用于窗口对象、登录弹窗等场景,优点包括易于维护、访问和低消耗,但也有安全隐患、可能形成巨石对象及扩展性差等缺点。文中展示了JavaScript和TypeScript的实现方法。
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
26 2
|
2月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
40 2
|
2月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
42 4
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
2月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
24 1
|
2月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
29 0
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
29 0
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
本教程详细讲解了Kotlin中的单例模式实现,包括饿汉式、懒汉式、双重检查锁、静态内部类及枚举类等方法,适合需要深入了解Kotlin单例模式的开发者。快速学习者可参考“简洁”系列教程。
41 0