---- AI试用 ---域名问题某些图片和js资源无法访问,导致一些代码实例无法运行!(代码里gzui.net换成momen.vip即可)

设计模式-单例模式(一)

前端开发 蚂蚁 631℃ 0评论

一、什么是单例模式

单例模式的定义是,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
有一些对象,比如线程池/全局缓存/浏览器中的 window 对象等等,我们只需要一个实例。下面将根据实际场景进行介绍。

二、实际场景

1. 登录浮窗

当我们单击登录按钮时,页面中会出现一个登录的浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。

1.1 传统做法

传统做法在页面加载完成时,就创建好登录浮窗,当用户点击登录按钮时,显示登录浮窗,实现代码如下:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <button id="loginBtn">登录</button>
    <script type="text/javascript" src="index.js">
    </script>
</body>
</html>
var loginLayer = (() => {
    let div = document.createElement('div')
    div.innerHTML = '我是登录弹窗'
    div.style.display = 'none'

    document.body.appendChild(div)

    return div
})()

document.getElementById('loginBtn').onclick = () => {
    loginLayer.style.display = 'block'
}

源码地址
上述代码有以下缺点:

在无需登录的情况下,也会新增登录浮窗的 DOM 节点,浪费性能。

现在优化一下,将代码改为,在用户点击登录按钮后,才新增登录浮窗的 DOM 节点。
代码如下:

var createLoginLayer = () => {
    let div = document.createElement('div')
    div.innerHTML = '我是登录弹窗'
    div.style.display = 'none'

    document.body.appendChild(div)

    return div
}

document.getElementById('loginBtn').onclick = () => {
    const loginLayer = createLoginLayer()
    loginLayer.style.display = 'block'
}

源码地址
上述代码也存在缺陷,具体如下:

每次点击登录按钮,都会创建一个登录浮窗,频繁的创建 DOM 节点更加浪费性能。

实际上,我们只需要创建一次登录浮窗。

1.2 单例模式

通过单例模式,重构上述代码。

const createLoginLayer = () => {
    const div = document.createElement('div')
    div.innerHTML = '我是登录弹窗'
    div.style.display = 'none'
    console.log(123)

    document.body.appendChild(div)
    return div
}

const createSingle = (function () {
    var instance = {}
    return function (fn) {
        if (!instance[fn.name]) {
            instance[fn.name] = fn.apply(this, arguments)
        }
        return instance[fn.name]
    }
})()

const createIframe = function () {
    const iframe = document.createElement('iframe')
    document.body.appendChild(iframe)
    iframe.style.display = 'none'
    return iframe
}

const createSingleLoginLayer = createSingle(createLoginLayer)
const createSingleIframe = createSingle(createIframe)

document.getElementById('loginBtn').onclick = () => {
    const loginLayer = createSingleLoginLayer
    const iframe = createSingleIframe
    loginLayer.style.display = 'block'
    iframe.style.display = 'block'
}

源码地址
经过重构,代码做了以下优化:

  • 将创建实例对象 createLoginLayer / createIframe 的职责和管理单例对象 createSingle 的职责分离,符合单一职责原则;
  • 通过闭包存储实例,并进行判断,不管点击登录按钮多少次,只创建一个登录浮窗实例
  • 易于扩展,当下次需要创建页面中唯一的 iframe / script 等其他标签时,可以直接复用该逻辑。

三、总结

单例模式是一种简单但非常实用的模式,特别是惰性单例技术,在合适的时候才创建对象,并且只创建唯一的一个。更奇妙的是,创建对象和管理单例的职责被分布在两个不同的方法中,这两个方法组合起来才具有单例模式的威力。

作者:清汤饺子
链接:https://juejin.cn/post/6967956673453359140
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转载请注明:有爱前端 » 设计模式-单例模式(一)

喜欢 (0)or分享 (0)