过完年了,让我们一起学习前端设计模式

过年假期已经接近尾声了,很多小伙伴是不是一样,准备返程搬砖了呢?今年过年跟往年也没有不一样,也就是在家吃吃喝喝,逗逗娃(侄子侄女),走走亲戚。本来今年想着不回老家的,怕被父母亲戚催婚,但后面想想今年家里房子刚装修,也想回去看看,另外也想吃到爸妈做的饭菜,还是回去了。可没曾想今年一个相亲对象都没给我介绍,说是去年介绍的被我谈崩了,老家已经没得适龄女青年了,不知道是喜是悲。

老家镇上买的新房(拒绝当房奴,实际上是穷)

一直有在掘金上看掘金小册的习惯,陆陆续续买了十几本,但真正看完就两三本。春节期间看完了《JavaScript 设计模式核心原理与应用实践》,想着拿前端比较常见的几种设计模式总结一下。

前端设计模式之一:单例模式

单例模式属于前端设计模式中创建型的一种,我们常见的前端状态管理工具Vuex和Redux都是采用单例模式,来实现了一个全局的 Store 用于存储应用的所有状态。当然它们具体的实现细节肯定不完全一样,但无疑都是应用了单例模式的思想。

单例模式的实现思路

一般情况下,当我们创建了一个类(本质是构造函数)后,可以通过new关键字调用构造函数进而生成任意多的实例对象。像这样:

javascript 复制代码
class SingleDog {
    show() {
        console.log('我是一个单例对象')
    }
}

const s1 = new SingleDog()
const s2 = new SingleDog()

// false
s1 === s2

但现在我们要思考这样一个问题:如何才能保证一个类仅有一个实例?

要做到这一点,就需要构造函数具备判断自己是否已经创建过一个实例的能力。我们现在把这段判断逻辑写成一个静态方法:

javascript 复制代码
class SingleDog {
    show() {
        console.log('我是一个单例对象')
    }
    static getInstance() {
        // 判断是否已经new过1个实例
        if (!SingleDog.instance) {
            // 若这个唯一的实例不存在,那么先创建它
            SingleDog.instance = new SingleDog()
        }
        // 如果这个唯一的实例已经存在,则直接返回
        return SingleDog.instance
    }
}

const s1 = SingleDog.getInstance()
const s2 = SingleDog.getInstance()

// true
s1 === s2

除了楼上这种实现方式之外,getInstance的逻辑还可以用闭包来实现:

javascript 复制代码
function SingleDogBase() {}SingleDogBase.prototype.show = function() {  console.log('我是一个单例对象')}
const SingleDog = (function() {
    // 定义闭包变量
    let instance = null
    return function() {
        if(!instance) {
            // 创建实例
            instance = new SingleDogBase()
        }
        return instance
    }
})()

const s1 = new SingleDog()const s2 = new SingleDog()

// ture
s1 === s2

可以看出,在已经创建的实例instance的判断和拦截下,我们不管调用多少次,SingleDog都只会给我们返回一个实例,s1和s2现在都指向这个唯一的实例。

单例模式应用之一:实现一个全局模态框

学会了单例如何创建,接下来让我们实现一个全局的模态框。

完整代码如下:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>单例模式弹框</title>
</head>
<style>
    #modal {
        height: 200px;
        width: 200px;
        line-height: 200px;
        position: fixed;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        border: 1px solid black;
        text-align: center;
    }
</style>
<body>
	<button id='open'>打开弹框</button>
	<button id='close'>关闭弹框</button>
</body>
<script>
    // 核心逻辑,这里采用了闭包思路来实现单例模式
    const Modal = (function() {
    	let modal = null
    	return function() {
            if(!modal) {
            	modal = document.createElement('div')
            	modal.innerHTML = '我是一个全局唯一的Modal'
            	modal.id = 'modal'
            	modal.style.display = 'none'
            	document.body.appendChild(modal)
            }
            return modal
    	}
    })()
    
    // 点击打开按钮展示模态框
    document.getElementById('open').addEventListener('click', function() {
        // 未点击则不创建modal实例,避免不必要的内存占用
    	const modal = new Modal()
    	modal.style.display = 'block'
    })
    
    // 点击关闭按钮隐藏模态框
    document.getElementById('close').addEventListener('click', function() {
    	const modal = new Modal()
    	if(modal) {
    	    modal.style.display = 'none'
    	}
    })
</script>
</html>

ES6 版本:

lua 复制代码
// class的静态方法实现  class Modal {    static getInstance() {      if (!Modal.instance) {        Modal.instance = document.createElement('div')        Modal.instance.innerHTML = '我是全局唯一的Modal'        Modal.instance.id = 'modal'        Modal.instance.style.display = 'none'        document.body.appendChild(Modal.instance)      }      return Modal.instance    }    static open() {      Modal.getInstance().style.display = 'block'    }    static close() {      Modal.getInstance().style.display = 'none'    }  }  const openBtn = document.getElementById('open')  const closeBtn = document.getElementById('close')  openBtn.addEventListener('click', function() {    Modal.open()  })  closeBtn.addEventListener('click', function() {    Modal.close()  })

以上代码大部分是小册的原代码,心里还有些忐忑是不是太水。但转念想想,对于自己算一种加深巩固,如果对掘友也能提供一点帮助,那也算一点贡献。有兴趣的同学可以购买大佬的小册深入学习一下,绝对是物有所值的。

小册地址:JavaScript 设计模式核心原理与应用实践 - 修言 - 掘金小册 (juejin.cn)

相关推荐
代码搬运媛4 小时前
Jest 测试框架详解与实现指南
前端
counterxing5 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq5 小时前
windows下nginx的安装
linux·服务器·前端
之歆6 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜6 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai108086 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
candyTong6 小时前
Claude Code 的 Edit 工具是怎么工作的
javascript·后端·架构
kyriewen8 小时前
产品经理把PRD写成“天书”,我用AI半小时重写了一遍,他当场愣住
前端·ai编程·cursor
humcomm8 小时前
元框架的工作原理详解
前端·前端框架
canonical_entropy9 小时前
Attractor Before Harness: AI 大规模开发的方法论
前端·aigc·ai编程