一个类只允许有一个实例,并且可以全局访问该实例 单例模式在实际开发中经常会用到,如用户点击弹出层,保持始终只有一个弹出层实例。下面我们循序渐进,先写一个最简单的单例
最简单的单例
我们用闭包延长作用域链,保存一个实例
const Single = function (name) {
this.name = name
}
Single.prototype.log = function () {
console.log(this.name)
}
Single.getInstance = (function () {
let instance = null
return function (name) {
if (!instance) {
instance = new Single(name)
}
return instance
}
})()
const tom = Single.getInstance('tom')
const bob = Single.getInstance('bob')
console.log(tom==bob); //true
- 首次getInstance的时候,没有实例,创建实例并保存;
- 再次getInstance,已经有实例,直接返回实例;
构造单例
上面创建单例的方式可能不是很直观,对于用户来说,至少需要知道通过Single.getInstance创建/访问单例子。我们采用更习惯的构造函数模式重构一下
const Single = (function () {
let instance = null
const CreateSingle = function (name) {
if (instance) {
return instance
}
this.name = name
return (instance = this)
}
CreateSingle.prototype.log = function () {
console.log(this.name)
}
return CreateSingle
})()
const tom = new Single('tom')
const bob = new Single('bob')
console.log(tom == bob) //true
单例代理
如果实际开发中需要很多单例模型,那我们就需要创建很多个单例类。我们是不是可以把单例管理的内容抽离出来呢?反正我们关心的只是一个类只有一个实例就行了,并不关心这个怎么保证生成单个实例。单例代理就是把保证只创建一个实例的逻辑抽离出来,开发者只需要创建单例类就行
//代理
const getSingle = function (fn) {
let result = null
return function () {
return result || (result = fn.apply(this, arguments))
}
}
那么接下来我们只需要传入单例类即可生成对应的单例了
//createDIV
const createDIV = function () {
const div = document.createElement('div')
div.innerHTML = '登录弹窗'
document.appendChild(div)
return div
}
const createSingleDiv = getSingle(createDIV)
//createText
const createText = function(content) {
const text = document.createTextNode(content)
return text
}
const createSingleText = getSingle(createText)