定义:
简明的定义:第一个对外有且仅有一个实例【只提供一个实例】,这种编码方案就是单件设计模式
应用场景:
- 1、vuex、React-Redux全局状态管理容器store对象
- 2、localStorage:相同协议、主机名、端口下只有一份localStorage
- 3、日志文件类(日志只有一个对象)
构建单件设计模式
- 1、构造器设置为私有,不允许外部创建类的实例
- 2、至少应该提供一个外部访问的方法或属性,通过它得到对象,所以这个方法应该是静态方法
- 3、外部调用静态方法获取一个对象
举个例子:
typescript
class MyLocalStorage {
static localStorage: MyLocalStorage
private constructor() {
}
public static getInstance() {
if(!this.localStorage) {
this.localStorage = new MyLocalStorage()
}
return this.localStorage
}
public setItem(key: string, value: any) {
localStorage.setItem(key, JSON.stringify(value))
}
public getItem(key: string) {
const value = localStorage.getItem(key)
return value ? JSON.parse(value) : null
}
}
静态方法相当于es5: 构造函数.静态方法
对象方法相当于es5: 构造函数.prototype.对象方法
实现一个Storage,使得该对象为单例,基于localStorage进行封装
实现方法setItem(key, value)和getItem(key)
javascript
// 静态方法版
class Storage {
static getInstance() {
// 判断是否已经new过1个实例
if(!Storage.instance) {
// 若这个唯一的实例不存在,那么先创建它
Storage.instance = new Storage()
}
// 如果这个唯一的实例已经存在,则直接返回
return Storage.instance
}
getItem(key) {
return localStorage.getItem(key)
}
setItem(key, value) {
return localStorage.setItem(key, value)
}
}
/**
* 测试代码
*
* const storage1 = Storage.getInstance()
* const storage2 = Storage.getInstance()
*
* storage1.setItem('name', 'zack')
* storage1.getItem('name') // zack
*
* storage2.getItem('name') // zack
*
* storage1 === storage2 // true
*
*
*
*/
javascript
// 闭包版
// 先实现一个基础的StorageBase类,把getItem和setItem方法放在它的原型链上
function StorageBase() {}
StorageBase.prototype.getItem = function(key) {
return localStorage.getItem(key)
}
StorageBase.prototype.setItem = function(key, value) {
return localStorage.setItem(key, value)
}
// 以闭包的形式创建一个引用自由变量的构造函数
const Storage = (function() {
let instance = null
return function() {
// 判断自由变量是否为null
if(!instance) {
// 如果为null则new出唯一实例
instance = new StorageBase()
}
return instance
}
})()
/**
* 测试代码
* // 这里不用new Storage的形式调用,直接Storage()也会有一样的效果
* const storage1 = new Storage()
* const storage2 = new Storage()
*
* storage1.setItem('name', 'zack')
*
* storage1.getItem('name') // zack
*
* storage2.getItem('name') // zack
*
* storage1 === storage2 // true
*
*
*/
实现一个全局的模态框(全局唯一的Modal弹框)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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实例,避免不必要的内存占用
// 此处不用new 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>