什么是单例模式
一句话介绍:保证类的实例只有一个。 单例模式更适用于重复访问的模块,保存其缓冲,避免重复调用和加载。 例如,我们的整个系统,有时需要一个唯一的全局变量,用来统一全局的配置和某些通用数据。这种模式有很广泛的实践,如 Vuex中对单例模式的使用。
如何实现
在javascript中,实现一个单例模式可以用一个变量来标志当前的类已经创建过对象,如果下次获取当前类的实例时,直接返回之前创建的对象即可,如下:
function CreateSingletion(name) {
this.name = name
}
CreateSingletion.prototype.getname = function () {
return this.name
}
const Singleton = function () {
let instance = null
return function (name) {
return instance || (instance = new CreateSingletion(name))
// 如果已经存在实例, 则返回存在的实例, 否则创建一个实例并赋值给result ,
// 下次调用时直接返回创建的实例
}
}()
const single1 = new Singleton('张三')
const single2 = new Singleton('李四')
console.log(single1, 'single1');
console.log(single2, 'single2');
console.log(Object.is(single1,single2));
打印输出结果
1.Vuex
很典型的单例模式的应用。Vuex的store就是一个单例模式。采用了单一状态树,一个对象即为唯一数据源。
// src/store.js
let Vue
export class Store {
constructor(options = {}) {
if (!Vue && typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
}
}
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
在Store的初始化时,只会执行一次install方法。在install方法中,会将Vue赋值,并将vuex的相关逻辑绑定到Vue实例上。可以看到Vuex在install的时候,判断是否有了唯一的数据。
2.弹框
这种实现称为惰性单例,意图解决需要时才创建类实例对象
<div id="loginBtn">弹窗</div>
function createLoginLayer() {
const div = document.createElement('div')
div.innerHTML = '我是浮窗';
div.style.display = 'none';
document.body.appendChild(div);
return div;
}
const singleLoginLayer = function (fn) {
let result = null
return function () {
return result || (result = fn.apply(this, arguments))
}
}
const createSingleLayer = singleLoginLayer(createLoginLayer)
document.querySelector('#loginBtn').addEventListener('click', () => {
// 单例模式, 每次调用只有一个
const loginLayerDom1 = createSingleLayer()
const loginLayerDom2 = createSingleLayer()
console.log(Object.is(loginLayerDom1, loginLayerDom2)); // 返回true
loginLayerDom1.style.display = 'block'
loginLayerDom2.style.display = 'block'
})
在使用单例模式的情况下,多次调用createSingleLayer()只会返回一个实例对象
在不使用单例模式的情况下,多次调用createLoginLayer()会返回多个实例对象
document.querySelector('#loginBtn').addEventListener('click', () => {
// 不是单例模式的情况下, 多次调用就显示多个
const noSingleDom1 = createLoginLayer()
const noSingleDom2 = createLoginLayer()
console.log(Object.is(noSingleDom1, noSingleDom2)); // 返回false
noSingleDom1.style.display = 'block'
noSingleDom2.style.display = 'block'
})