單例模式的定義:保證一個(gè)類僅有一個(gè)實(shí)例飞蛹,并提供一個(gè)訪問它的全局訪問點(diǎn)
1剥懒,簡(jiǎn)單實(shí)現(xiàn)
var Singleton = function (name) {
this.name = name
}
Singleton.instance = null
Singleton.prototype.getName = function () {
console.log(this.name)
}
Singleton.getInstance = function (name) {
if (!this.instance) {
this.instance = new Singleton(name)
}
return this.instance
}
var a = Singleton.getInstance('a')
var b = Singleton.getInstance('b')
console.log(a === b)
或者:
var Singleton = function (name) {
this.name = name
}
Singleton.prototype.getName = function () {
console.log(this.name)
}
Singleton.getInstance = (function () {
var instance = null
return function (name) {
if (!instance) {
instance = new Singleton(name)
}
return instance
}
})()
//所謂單例模式内舟,就是只有一個(gè)對(duì)象實(shí)例
var a = Singleton.getInstance('a')
var b = Singleton.getInstance('b')
console.log(a === b)
在這段代碼中,我們需要通過Singleton.getInstance來獲取Singleton的實(shí)例初橘,使用者必須知道Singleton類是一個(gè)單例類验游,這增加了代碼的“不透明性”,通過Singleton.getInstance獲取對(duì)象的方式也與一般的new方法獲取不同保檐。這段單例模式代碼的意義不大
2耕蝉,透明的單例模式
//透明的單例模式
var CreateDiv = (function () {
var instance
var CreateDiv = function (html) {
if (instance) {
return instance
}
this.html = html
this.init()
return instance = this
}
CreateDiv.prototype.init = function () {
//node里面沒有document,會(huì)報(bào)錯(cuò)
var div = document.createElement('div')
div.innerHTML = this.html
document.body.appendChild(div)
}
return CreateDiv
})()
var a = new CreateDiv('a')
var a = new CreateDiv('b')
現(xiàn)在我們實(shí)現(xiàn)了一個(gè)透明的單例類的編寫夜只,但仍有一些問題
CreateDiv類中實(shí)際上有兩個(gè)功能:創(chuàng)建對(duì)象和執(zhí)行初始化init方法垒在、保證只有一個(gè)對(duì)象。不符合單一職責(zé)原則扔亥。
當(dāng)我們需要取消單例场躯,變成一個(gè)正常的構(gòu)造函數(shù)時(shí),修改代碼會(huì)帶來一些不必要的麻煩
3旅挤,透明單例改-代理模式
// 用代理實(shí)現(xiàn)代理模式
var CreateDiv = function (html) {
this.html = html
this.init()
}
CreateDiv.prototype.init = function () {
var div = document.createElement('div')
CreateDiv.innerHtml = this.html
document.body.appendChild(div)
}
var ProxySingletonCreateDiv = (function () {
var instance
return function (html) {
if (!instance) {
instance = new CreateDiv(html)
}
return instance
}
})()
var a = ProxySingletonCreateDiv('a')
var b = ProxySingletonCreateDiv('b')
console.log(a === b)
現(xiàn)在踢关,負(fù)責(zé)管理單例的的邏輯在ProxySingletonCreateDiv中實(shí)現(xiàn),CreateDiv就是一個(gè)普通的類粘茄,美滋滋
4签舞,惰性單例
惰性單例指的是在需要的時(shí)候才創(chuàng)建對(duì)象實(shí)例秕脓。惰性單例是單例模式的重點(diǎn)。
在javaScript中儒搭,基于類的單例模式并不適用吠架,需要轉(zhuǎn)變思路
4.1,彈框功能
var loginLayer = (function () {
var div = document.createElement('div')
div.innerHTML = '我要登錄搂鲫,不給就送'
div.style.display = 'none'
document.body.appendChild(div)
return div
})()
document.getElementById('loginBtn').onclick = function () {
loginLayer.style.display = 'block'
}
缺點(diǎn):loginLayer在頁面進(jìn)來之后就直接執(zhí)行了傍药,如果用戶不需要這個(gè)彈框,很浪費(fèi)
4.2魂仍,彈框功能節(jié)約版
var createLoginLayer = function () {
var div = document.createElement('div')
div.innerHTML = '我要登錄怔檩,不給就送'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
document.getElementById('loginBtn').onclick = function () {
var loginLayer = createLoginLayer()
loginLayer.style.display = 'block'
}
雖然節(jié)約了,但是每次點(diǎn)擊的時(shí)候都會(huì)創(chuàng)建新的div蓄诽,失去了單例的效果
4.3薛训,彈框功能單例版
var createLoginLayer = (function () {
var div
return function () {
if (!div) {
div = document.createElement('div')
div.innerHTML = '我要登錄,不給就送'
div.style.display = 'none'
document.body.appendChild(div)
}
return div
}
})()
document.getElementById('loginBtn').onclick = function () {
var loginLayer = createLoginLayer()
loginLayer.style.display = 'block'
}
確實(shí)實(shí)現(xiàn)了單例的功能仑氛,但是彈框的創(chuàng)建和管理(if(!div) return div這段控制返回的代碼)都在createLoginLayer中實(shí)現(xiàn)乙埃,違反了單一職責(zé)原則
4.4,彈框功能OK版
var getSingle = function (fn) {
var result
return function () {
return result || (result = fn.apply(this, arguments))
}
}
var createLoginLayer = function () {
var div = document.createElement('div')
div.innerHTML = '我要登錄锯岖,不給就送'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
var createSingleLoginLayer = getSingle(createLoginLayer)
document.getElementById('loginBtn').onclick = function () {
var loginLayer = createSingleLoginLayer()
loginLayer.style.display = 'block'
}
good介袜!