浅聊一下
设计模式是我们必不可少的编程素养,今天我们要聊的是百度考题——单例模式
es6新增 “类”
要讲单例模式,我们就从es6新增的类开始说起,我们先来看代码
class SingleDog{
show(){
console.log('我是一个单例对象');
}
}
const s1 = new SingleDog();
const s2 = new SingleDog();
console.log(s1 === s2);
这段代码定义了一个类,名字叫SingleDog
,我们创建了两个SingleDog
的实例对象s1和s2,打印一下他们的结果,这并不难理解,因为创建的s1和s2所存储的地址不同,他们是相同类的不同实例对象,于是乎,打印的结果肯定是 false
那么跟我们今天要讲的单例模式有什么关系呢?我们先来了解一下单例模式到底是什么…
单例模式
当我们谈论单例模式时,我们指的是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
什么意思?就是说在我上面的SingleDog类只能有一个实例对象,不管你创建了多少个对象,都会返回创建的第一个对象…那该咋办?我们得用到static
static
在 JavaScript 中,
static
是一个关键字,用于定义类的静态属性和静态方法。静态成员属于类本身,而不是类的实例。
讲的这么深奥,我还是看不懂…那就直接上代码
class SingleDog{
//属于对象的
show(){
console.log('我是一个单例对象');
}
// 不要直接new
// 属于类的
static getInstance(){
console.log('静态方法');
}
}
当我们要使用show()
方法时,我们得创建一个SingleDog
的实例对象,然后再通过实例对象来调用show()方法
const s1 = new SingleDog()
s1.show()
而当我们想要调用static方法的时候,不用创建直接调用
SingleDog.getInstance()
实现单例模式
我们已经掌握了static,那么我们怎么来实现单例模式呢?
class SingleDog{
//属于对象的
show(){
console.log('我是一个单例对象');
}
// 不要直接new
// 属于类的
static getInstance(){
// console.log('静态方法');
if(!SingleDog.instance){
SingleDog.instance = new SingleDog();
}
return SingleDog.instance;
}
}
static getInstance
是一个静态方法,它属于类本身而不是类的实例。通过 static
关键字声明的静态方法可以直接通过类名调用,无需创建类的实例。在这个例子中,getInstance
方法的作用是返回 SingleDog
类的一个实例。
- 在
getInstance
方法内部,首先检查静态属性instance
是否已经存在实例。如果不存在,就创建一个新的SingleDog
实例,并将其赋值给instance
属性。 - 随后,无论是否创建了新实例,都会返回
instance
属性的值,确保始终返回同一个实例。
通过这种设计,你可以确保 SingleDog
类的实例始终只有一个,因为 getInstance
方法在每次调用时都会返回相同的实例。这就是所谓的单例模式,它确保一个类只有一个实例,并提供了一个全局访问点以确保所有代码都在使用相同的实例。
使用静态方法来实现单例模式是一种常见的做法,因为它允许你在不创建实例的情况下访问类的方法,并且能够控制类的实例化过程。
百度考题-写一个弹窗
百度考题呀,让你写一个弹窗,实际上就是要你写一个单例模式,你点击一个按钮,弹出弹窗,点击关闭,弹窗关闭,无论你点击多少个按钮,无论你点击多少次按钮,弹窗始终是最开始的那个弹窗…
理解了上面讲的内容,想要写出来并不难
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录框</title>
<style>
#modal{
width: 200px;
height: 200px;
background-color: #ccc;
line-height: 200px;
text-align: center;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border: 1px solid #000;
}
</style>
</head>
<body>
<button id="open">打开弹窗</button>
<button id="close">关闭弹窗</button>
<script>
//立即执行函数
// 闭包的方式实现单例
const Modal = (function(){
//创建闭包
let modal = null//自由变量
return function(){
if(!modal){
modal = document.createElement('div')
modal.innerHTML = '我是全局唯一的登录框'
modal.style.display = 'none'
modal.id = 'modal'
document.body.appendChild(modal)
}
return modal
}
})()
// const modal = new Modal()
document.getElementById('open').addEventListener('click',function(){
const modal = new Modal();
modal.style.display = 'block'
})
document.getElementById('close').addEventListener('click',function(){
const modal = new Modal();
modal.style.display = 'none'
})
</script>
</body>
</html>
- 定义立即执行函数
const Modal = (function(){
// ...
})()
这里定义了一个匿名函数,并立即执行它。由于括号 ()
包裹在函数声明的外部,所以该函数会立即执行。同时,在函数内部定义了一个闭包,用于实现单例模式。
- 创建闭包
let modal = null;
return function() {
// ...
}
在闭包内部,定义了一个自由变量 modal
,初始值为 null
。然后,返回一个函数,该函数可以访问并操作 modal
变量,也就是实现了闭包。如果还有不会闭包的掘友可以去看我的文章(深入探讨:闭包的神秘面纱 – 掘金 (juejin.cn))
- 实现单例模式
if (!modal) {
modal = document.createElement('div');
// ...
return modal;
}
在闭包内部的函数中,首先判断 modal
变量是否已经存在。如果不存在,则创建登录框元素,并将其添加到 body
中,然后将 modal
变量赋值为该元素。最后,返回 modal
变量。这样,下次再调用该函数时,就会直接返回之前创建的登录框元素,而不会重复创建。
- 使用单例模式
document.getElementById('open').addEventListener('click', function() {
const modal = new Modal();
modal.style.display = 'block';
});
document.getElementById('close').addEventListener('click', function() {
const modal = new Modal();
modal.style.display = 'none';
});
在页面中,有两个按钮,一个用于打开登录框,一个用于关闭登录框。当用户点击打开按钮时,代码会调用 Modal
函数来获取或创建登录框元素,然后将其显示出来。当用户点击关闭按钮时,代码也调用 Modal
函数来获取或创建登录框元素,然后将其隐藏。
来看看效果:
点击打开弹窗,new了一个新的DOM结点,此时display为block
点击关闭弹窗,让DOM结点display为none
再次点击打开弹窗,不会新建一个DOM,而是让原来的DOMdisplay为block…题目完成
结尾
在实际应用中,合理地运用设计模式能够提高代码质量、可读性和可维护性,是每个开发者都应该掌握的技能之一。希望本篇内容能对你有所帮助,如果有任何疑问或者想继续探讨其他主题,都可以随时提出哦!
原文链接:https://juejin.cn/post/7333236033038090281 作者:滚去睡觉