# 什么是单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就是单例模式。
# 单例理模式的实现
下面我们用两种方式来实现单例模式。
第一种方式使用静态方法。
class SingleTon {
static getInstance() {
return !SingleTon.instance ? SingleTon.instance = new SingleTon() : SingleTon.instance
}
}
console.log(SingleTon.getInstance() === SingleTon.getInstance()) // true
第二种方式,使用闭包。
class SingleTon {}
SingleTon.getInstance = (function() {
let instance = null
return function() {
return !instance ? instance = new SingleTon() : instance
}
})()
console.log(SingleTon.getInstance() === SingleTon.getInstance())
# Vuex中的单例模式
下面是Vuex中install方法的简化版:
let Vue
export function install(_Vue) {
// 判断传入的vue实例对象是否已经被install过Vuex插件
if (Vue && _Vue === Vue) return
// 若没有,则为这个Vue实例对象install一个唯一Vuex
Vue = _Vue
// 将Vuex的初始化逻辑编写进Vue的钩子函数里
applyMixin(Vue)
}
如果Vuex的install方法中没有实现单例模式,如果我们多次调用了install方法就有可能对数据产生覆盖。
# 实战
实战一
实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)
方法一:
class Storage {
static getInstance() {
return !Storage.instance ? Storage.instance = new Storage() : Storage.instance
}
getItem(key) {
return localStorage.getItem(key)
}
setItem(key, value) {
localStorage.setItem(key, value)
}
}
方法二:
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(){
return !instance ? instance = new StorageBase() : instance
}
})()
实战二
实现一个全局唯一的Modal弹框
<!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实例,避免不必要的内存占用;此处不用 new Modal 的形式调用也可以,和 Storage 同理
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>