一、概念
保障一个类仅有一个实例,并提供一个拜访它的全局拜访点,这样的模式就叫做单例模式。
单例模式是设计模式中绝对较为容易了解、容易上手的一种模式,同时因为其具备宽泛的利用场景,也是面试题里的常客。
二、实现思路
当初咱们先不思考单例模式的利用场景,单看它的实现,思考这样一个问题:如何能力保障一个类仅有一个实例?
个别状况下,当咱们创立了一个类(实质是构造函数)后,能够通过 new 关键字调用构造函数进而生成任意多的实例对象。像这样:
class SingleDog {show() {console.log('我是一个单例对象')
}
}
const s1 = new SingleDog()
const s2 = new SingleDog()
// false
s1 === s2
咱们先 new 了一个 s1,又 new 了一个 s2,很显著 s1 和 s2 之间没有任何瓜葛,两者是互相独立的对象,各占一块内存空间。而单例模式想要做到的是,不论咱们尝试去创立多少次,它都只给你返回第一次所创立的那惟一的一个实例。
要做到这一点,就须要构造函数 具备判断本人是否曾经创立过一个实例的能力。咱们当初把这段判断逻辑写成一个静态方法(其实也能够间接写入构造函数的函数体里):
三、简略 demo
class SingleDog {show() {console.log('我是一个单例对象')
}
static getInstance() {
// 判断是否曾经 new 过 1 个实例
if (!SingleDog.instance) {
// 若这个惟一的实例不存在,那么先创立它
SingleDog.instance = new SingleDog()}
// 如果这个惟一的实例曾经存在,则间接返回
return SingleDog.instance
}
}
const s1 = SingleDog.getInstance()
const s2 = SingleDog.getInstance()
// true
s1 === s2
除了以上这种实现办法,也能够利用 闭包 来实现:
SingleDog.getInstance = (function() {
// 定义自在变量 instance,模仿公有变量
let instance = null
return function() {
// 判断自在变量是否为 null
if(!instance) {
// 如果为 null 则 new 出惟一实例
instance = new SingleDog()}
return instance
}
})()
四、扩大
1.Vuex 中的单例模式
Vuex 应用繁多状态树,用一个对象就蕴含了全副的利用层级状态。至此它便作为一个“惟一数据源 (SSOT)”而存在。这也意味着,每个利用将仅仅蕴含一个 store 实例。繁多状态树让咱们可能间接地定位任一特定的状态片段,在调试的过程中也能轻易地获得整个以后利用状态的快照。——Vuex 官网文档
在 Vue 中,组件之间是独立的,组件间通信最罕用的方法是 props(限于父组件和子组件之间的通信),略微简单一点的(比方兄弟组件间的通信)咱们通过本人实现简略的事件监听函数也能解决掉。
但当组件十分多、组件间关系简单、且嵌套层级很深的时候,这种原始的通信形式会使咱们的逻辑变得复杂难以保护。这时最好的做法是将共享的数据抽出来、放在全局,供组件们依照肯定的的规定去存取数据,保障状态以一种可预测的形式发生变化。于是便有了 Vuex,这个用来寄存共享数据的惟一数据源,就是 Store。
Vuex 如何确保 Store 的唯一性
咱们先来看看如何在我的项目中引入 Vuex:
// 装置 vuex 插件
Vue.use(Vuex)
// 将 store 注入到 Vue 实例中
new Vue({
el: '#app',
store
})
通过调用 Vue.use()办法,咱们装置了 Vuex 插件。Vuex 插件是一个对象,它在外部实现了一个 install 办法,这个办法会在插件装置时被调用,从而把 Store 注入到 Vue 实例里去。也就是说每 install 一次,都会尝试给 Vue 实例注入一个 Store。
在 install 办法里,有一段逻辑和咱们楼上的 getInstance 十分类似的逻辑:
let Vue // 这个 Vue 的作用和楼上的 instance 作用一样
...
export function install (_Vue) {
// 判断传入的 Vue 实例对象是否曾经被 install 过 Vuex 插件(是否有了惟一的 state)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 实例对象 install 一个惟一的 Vuex
Vue = _Vue
// 将 Vuex 的初始化逻辑写进 Vue 的钩子函数里
applyMixin(Vue)
}
以上便是 Vuex 源码中单例模式的实现方法了,套路能够说和咱们的 getInstance 一模一样。通过这种形式,能够保障一个 Vue 实例(即一个 Vue 利用)只会被 install 一次 Vuex 插件,所以每个 Vue 实例只会领有一个全局的 Store。