前言:从 JavaScript 函数的"二义性"说起
在深入单例模式之前,我们需要理解 JavaScript 中函数的一个有趣特性——二义性。这种特性既是 JavaScript 灵活性的体现,也是许多困惑的源头。
什么是函数的二义性?
function Person(){
this.name='汉堡'
return 'dssd'
}
let p=new Person()//创建一个实例对象{name:'汉堡'}
let s=Person()//创建一个函数体
很显然上面这个Person这个函数有两层用法一种是直接当成函数体来调用,还有一种就是直接用new来调用它,导致会创建一个实例对象。所以很多初学者就会觉得非常奇怪,于是在ECMAScript 6这个版本中官方打造了新的方法叫做类,我们现在就可以直接这样写,来消除函数的二义性。
class Person{//类
constructor()
{
this.name='学生'
}
}
let p=new Person()
这样得到的p就是一个实例对象
单例模式:确保唯一性
单例模式:保证一个类只有一个实例,并提供一个访问它的全局作用点。这段话说的太官方了,我们直接上代码
class Person{//类
constructor(){
this.name='学生'
}
}
let p=new Person()
let s=new Person()
console.log(p==s);//false
这里我创建了一个Person这个类,并且通过new来生成了两个实例对象s和p,很显然它们并不相同,因为每次都申请了一个不同的地址来创建这个实例对象。这时候我想这类每次生成地实例对象都是同一个,就可以通过static和闭包来创建一个单例模式。
static
- 在 JavaScript 中,
static是一个关键字,用于定义类的静态属性和静态方法。静态成员属于类本身,而不是类的实例。
class Dog{
show(){
console.log('单例');
}
static get(){
if(!Dog.get){
Dog.get=new Dog()
}
return Dog.get
}
}
let p1=Dog.get
let p2=Dog.get
console.log(p1==p2);//ture
这里get函数每次返回的就都是同一个实例对象,静态函数只能被类访问,而不能被它的实例对象访问。
闭包
- 当调用一个外部函数中返回的内部函数后,即使外部函数执行结束,但是内部函数依然引用了外部函数的变量,那么外部函数的执行上下文就不能完全销毁,而是会保留一个集合,用来装内部函数需要引用的变量,我们把集合称之为闭包。
class SingleDog {
show() {
console.log('我是一个单例对象');
}
}
SingleDog.getInstance = (function() {
let instance=new SingleDog()
return function() {
return instance
}
})()
const s1 = SingleDog.getInstance()
const s2 = SingleDog.getInstance()
console.log(s1 === s2);
这时候函数function返回的就是同一个实例对象instance
实现单例弹窗
就是让你写一个带有单例模式的弹窗,让你每次无论点哪个按钮关闭或者打开弹窗都是同一个弹窗。代码如下先写
<!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;
line-height: 200px;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 1px solid #000;
text-align: center;
}
</style>
</head>
<body>
<button id="btn1">open1</button>
<button id="btn2">open2</button>
<button id="close">close</button>
<script>
const Modal = (function () {
let modal = null
return function () {
if (!modal) {
modal = document.createElement('div')
modal.innerHTML = '我是一个全局弹框' // <div id="modal">我是一个全局弹框</div>
modal.id = 'modal'
modal.style.display = 'none'
document.body.appendChild(modal) //
}
return modal
}
})()
document.getElementById('btn1').addEventListener('click', function () {
const modal = new Modal()
modal.style.display = 'block'
})
document.getElementById('btn2').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>
就是先创建三个按钮,再写一个弹窗里面带有单例模式先隐藏,最后给每个按钮绑定一个点击事件,这样每次打开关闭弹窗就是同一个
总结
熟悉的掌握单例模式可以让代码更加美观简洁,提高代码质量,可读性,在实际应用场景中,同样也有很多地方用得上单例模式,这同样也是高频面试考点