JavaScript设计模式之单例模式详解

 更新时间:2024年08月09日 08:25:17   作者:Alo365  
单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问该实例的方式,这在某些场景下非常有用,例如配置管理类、日志类或数据库连接管理类,需要的朋友可以参考下

什么是单例模式

单,单个;例,实例。顾名思义,单例设计模式就是限制一个类必须只能有一个类,如果第二次创建的时候,我们可以抛出错误或者返回第一次的实例。

我们知道当new一个构造函数时就会得到一个实例对象,new的执行原理如下:

function Person() {
  // let obj = {   // 1
  //   name: 'Tom'   // 3的效果
  // }
  // Person.call(obj) // 2 让Person构造函数的this指向obj
  // obj.__proto__ = Person.prototype  // 4   //让实例对象的隐式原型等于构造函数的显示原型
  // return obj  // 5 返回实例对象
  
  this.name = 'Tom'  // 3 往obj上添加属性
  
  let p1 = new Person()
   let p2 = new Person()

 console.log(p1 === p2);//false
}

当使用 new 关键字创建一个对象时,每次都会生成一个新的实例,这意味着每个对象都有自己独立的内存空间和引用地址。因此,即使两个对象是由同一个类或构造函数创建的,它们的引用地址也是不同的。

而单例模式就是要我们不管new多少次,都得到相同的这个对象。

实现方法

一、采用static静态方法

静态方法在类本身上定义,不依赖于类的实例。所以静态方法只能被类访问,不能被实例对象访问

  • 全局访问:静态方法提供了一个类级别的全局访问点,可以在不实例化类的情况下调用。

  • 实例管理:静态方法可以操作静态属性来存储和管理唯一实例,从而确保实例的唯一性。

示例代码

class Person {
constructor() {
 this.name = 'Tom'  //初始化name属性
}
static getInstance() {//静态方法,用于创建或获取 Person的唯一实例
 if (!Person.instance) {//如果不存在,则创建一个新的 实例
   Person.instance = new Person()
 }
 return Person.instance//将其赋值给Person.instance
}
}

let p1 = Person.getInstance()
let p2 = Person.getInstance()

console.log(p1 === p2)//true

二、闭包

1. 闭包的基本概念

闭包是一个函数和其相关的词法环境的组合,这个环境包含了该函数的作用域中的所有变量。

在JavaScript中,闭包允许函数访问其外部作用域中的变量,即使函数在外部作用域之外被调用时,也可以保留对这些变量的访问权限。

2. 单例模式的需求

单例模式需要以下特性:

  • 唯一实例:保证类在整个应用程序中只有一个实例。
  • 全局访问:提供一个全局访问点来获取这个唯一实例。

3. 使用闭包实现单例模式

闭包可以通过封装实例的创建和管理逻辑来实现单例模式。具体来说,闭包可以帮助我们创建一个私有作用域来保存唯一实例,从而控制实例的唯一性。

示例代码

class Person {
  constructor() {
    this.name = 'Tom'
  }
  static getInstance() {
    let instance = null
    return function() {
      if (!instance) {
        instance = new Person()
      }
      return instance
    }
  }
}

const simple = Person.getInstance()
let p1 = simple()
let p2 = simple()

console.log(p1 === p2);

这段代码中关于闭包的使用:

  • 每次调用返回的匿名函数时,闭包会记住 instance 变量的值。
  • 如果 instancenull,则创建一个新的 Person 实例,并将其赋值给 instance 变量。
  • 如果 instance 已经存在,则直接返回这个实例。
  • 闭包创建了一个私有作用域,在这个作用域内管理 instance 变量,使其不会被外部代码直接访问或修改。这确保了只有一个实例能够被创建,并且所有对该实例的访问都通过同一个方法。

应用场景

这里我们用一段 HTML 进行简单演示,展示如何通过单例模式来管理浏览器的 localStorage 数据存取。在某些场景下,我们需要确保对 localStorage 的操作是由同一个实例来执行的,避免重复创建对象,确保数据的一致性。

<body>
  <button id="save">存储</button>
  <button id="get">取值</button>

  <script>
    let save = document.getElementById('save')
    let get = document.getElementById('get')

    // 定义一个Storage类,用单例模式封装LocalStorage操作
    class Storage {
      // 使用静态方法实现单例模式
      static getInstance() {
        if (!Storage.instance) {
          Storage.instance = new Storage();
        }
        return Storage.instance;
      }

      // 获取LocalStorage中的数据
      getItem(key) {
        return localStorage.getItem(key);
      }

      // 存储数据到LocalStorage
      setItem(key, val) {
        return localStorage.setItem(key, val);
      }
    }

    // 获取唯一的Storage实例
    const storage = Storage.getInstance();
    const storage2 = Storage.getInstance();
    
    // 点击存储按钮,保存数据到LocalStorage
    save.onclick = function() {
      storage.setItem('name', '高老师');
    }

    // 点击取值按钮,弹出LocalStorage中的数据
    get.onclick = function() {
      alert(storage2.getItem('name'));
    }

  </script>
</body>
</html>

代码解读

  • HTML 结构
    页面中包含两个按钮,分别用于“存储”和“取值”操作。通过 id 获取按钮元素,并绑定相应的点击事件。

  • Storage 类的定义
    Storage 类封装了对 localStorage 的操作,并通过静态方法 getInstance 实现单例模式。这个方法确保 Storage 类在整个应用中只有一个实例,这样对 localStorage 的访问都是通过同一个对象进行的。

  • 按钮事件处理

    • 点击“存储”按钮时,Storage 实例的 setItem 方法将 '高老师' 存储在 localStorage 中,键名为 'name'
    • 点击“取值”按钮时,Storage 实例的 getItem 方法读取 localStorage 中存储的 'name',并通过弹窗显示出来。

结果验证

在这段代码中,无论你点击多少次“存储”或“取值”按钮,所有的操作都会通过同一个 Storage 实例进行。这保证了数据的一致性,并且利用单例模式避免了不必要的对象创建。

应用优势

通过这种封装方式,我们可以更方便地管理和扩展与 localStorage 相关的操作,同时避免了全局状态的混乱。此外,单例模式的使用确保了在整个应用程序中,只会存在一个 Storage 实例,简化了管理,减少了内存消耗。

以上就是JavaScript设计模式之单例模式详解的详细内容,更多关于JavaScript单例模式的资料请关注脚本之家其它相关文章!

相关文章

  • JS实现拼音(字母)匹配汉字(姓名)的示例代码

    JS实现拼音(字母)匹配汉字(姓名)的示例代码

    这篇文章主要为大家详细介绍了如何利用JavaScript实现拼音(字母)匹配(搜索)汉字(姓名)的效果,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-04-04
  • 基于Bootstrap 3 JQuery及RegExp的表单验证功能

    基于Bootstrap 3 JQuery及RegExp的表单验证功能

    这篇文章主要介绍了基于Bootstrap 3 JQuery及RegExp的表单验证功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02
  • JS技巧动手实现红包兔子雨效果示例详解

    JS技巧动手实现红包兔子雨效果示例详解

    这篇文章主要为大家介绍了JS技巧动手实现红包兔子雨效果示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

    BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

    这篇文章主要介绍了BootstrapTable与KnockoutJS相结合实现增删改查功能【二】的相关资料,非常具有参考价值,感兴趣的朋友一起学习吧
    2016-05-05
  • bootstrap输入框组代码分享

    bootstrap输入框组代码分享

    Bootstrap 支持的另一个特性,输入框组,输入框组扩展自表单控件.下面小编给大家介绍bootstrap输入框组的代码,非常不错具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-06-06
  • javascript中字符串处理常用的方法汇总

    javascript中字符串处理常用的方法汇总

    JavaScript中操作字符串是一个很重要的话题,下面这篇文章主要给大家介绍了关于javascript中字符串处理常用的方法,文中通过图文以及代码示例介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • 用window.onerror捕获并上报Js错误的方法

    用window.onerror捕获并上报Js错误的方法

    这篇文章主要介绍了用window.onerror捕获并上报Js错误的方法,需要的朋友可以参考下
    2016-01-01
  • 基于ts的动态接口数据配置的详解

    基于ts的动态接口数据配置的详解

    这篇文章主要介绍了基于ts的动态接口数据配置的详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 一波JavaScript日期判断脚本分享

    一波JavaScript日期判断脚本分享

    这篇文章主要介绍了一波JavaScript日期判断脚本分享,包括计算日期是否在时间段内即闰年的判断等,需要的朋友可以参考下
    2016-03-03
  • javascript实现随机显示星星特效

    javascript实现随机显示星星特效

    这篇文章主要介绍了javascript实现随机显示星星特效的相关资料,以一个完整实例形式较为详细的分析了js实现随机显示星星特效的实现技巧,需要的朋友可以参考下
    2016-01-01

最新评论