当前位置:数据分析 > 这是如何在 JavaScript 中使用单例模式

这是如何在 JavaScript 中使用单例模式

  • 发布:2023-10-01 17:09

如果你想让你的代码更加优雅、可维护、简洁,往往离不开设计模式的解决方案。

在JS设计模式中,核心思想是:变化的封装(将变化与不变性分开,保证变化的部分灵活,不变的部分稳定)。

单例模式

那么我们来谈谈第一个常见的设计模式:单例模式

单例模式保证一个类只有一个实例,并提供全局访问方法来访问它。为了解决一个全局使用的类被频繁创建和销毁而占用内存的问题。

通过 ES5 中的闭包

在ES5中,可以使用闭包(函数内部的返回函数被外部​​变量引用,导致这个函数内的变量没有被释放,所以构造为闭包)来保存该类的实例。

var Singeton = (函数(){
    var 实例;
    
    函数用户(姓名,年龄){
        www.sychzs.cn=名称;
        this.age=年龄;
    }
    
    返回函数(姓名,年龄){
        如果(!实例){
            实例=新用户(姓名,年龄)
        }
        返回实例
    }
})()

此时一旦生成了这个实例,每次都会返回这个实例,并且不会被修改。你可以看到下面的代码。当User对象最初被分配name:alice,age:18时,可以稍后再分配。无效,每次都返回初始实例对象。

使用ES6中类的静态属性

上面的代码使用ES6语法实现,通过类的静态属性保存唯一的实例对象。

 类辛格顿{
    构造函数(姓名,年龄){
        if(!Singeton.instance){
            www.sychzs.cn = 名称;
            this.age = 年龄;
            Singleton.instance = this;
        }

       返回Singeton.instance;
    }
}

创建方法还是一样,使用new关键字创建类的实例对象。

案例

那么这样的设计模式在开发中实际有什么用呢?我们想象一个这样的业务场景:访问一个网站时,该页面已经很长时间没有操作了。此时,授权已过期。当我们点击页面上的任意位置时,就会弹出一个登录框。

那么这个登录框是全局唯一的,不会有多个副本,也不会相互冲突,所以不需要每次都创建副本,保留第一个即可。

提前创建节点

我们可能会想到先在页面中提前创建节点,编写页面样式,最后控制元素的显示属性,达到显示和隐藏的效果。








这样就可以满足要求了。全局只有一个登录框,并且每次都显示相同的登录框。但问题是 DOM 元素是从一开始就被创建并添加到主体中的。不管是否需要,如果有些场景不需要登录,那么这里的初始渲染就会浪费空间。

单箱模式

如果不需要初始渲染,只在需要时使用,并且每次都返回相同的实例,如何实现单例模式?

我们可以这样处理




上面的方法虽然可以达到效果,但是创建对象和管理单例的逻辑都放在了对象内部,有点混乱。如果下次需要在页面中创建唯一的 iframe 或 script 标签,则必须复制上述函数。

通用单件

首先拆分功能逻辑,取出执行对象创建的逻辑

const createLayer = 函数(){
  让 div = document.createElement("div")
  div.innerHTML = "登录对话框"div.className = "模态"
  div.style.display = "无"
  document.body.appendChild(div);
  返回div;
}

const 模态 = (函数(){
  让实例=空
  返回函数(){
      如果(!实例){
          实例=创建图层()
      }
      返回实例
  }
})()

经过上述修改后,代码逻辑会更加清晰,但是此时,不支持其他组件的通用创建。这个时候我们要思考如何优化创建单例的方法,以及单例是否需要被执行。函数抽象。

const createSingle = (函数(fn){
    让实例;
    返回函数(){
        返回实例|| ( 实例 = fn.apply(this, 参数))
    }
})()

经过这样的改造,如果有创建iframe的方法,也可以直接使用。

const createIframe = function() {
  const iframe = document.createElement('iframe');
  iframe.style.display = '无';
  document.body.appendChild(iframe);
  返回 iframe
}
const singleIframe = createSingle(createIframe)

document.querySelector("#open").onclick = function(){
 常量 iframe = singleIframe()
 iframe.style.display = '块'
}

实际应用

以上是我们的小尝试,我们来看看社区中一些很棒的实现吧~比如:React中常用的状态管理工具Redux,采用的是单例模式,就有这样的需求。

  • 单一数据源:整个应用程序状态仅存在于一个存储中。
  • State 是只读的:不要直接更改state 的值。改变状态的唯一方法是触发一个动作。
  • reducer 是一个纯函数:需要编写一个纯函数reducer 来修改state 的值。

我们看一下Redux的源码。为了方便阅读,删除了一些逻辑判断和评论。可以看到闭包中的currentState每次都是通过store的getState方法获取的。

单例模式内存中只有一个实例,可以减少内存开销。它还可以在系统中设置全局接入点,以优化和共享资源。

以上就是单例模式的相关介绍。更多关于前端设计模式,可以参考我的其他博文,会持续更新~

相关文章