單例模式的定義:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點
1,簡單實現
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
}
})()
//所謂單例模式,就是隻有一個對象實例
var a = Singleton.getInstance('a')
var b = Singleton.getInstance('b')
console.log(a === b)
在這段代碼中,我們需要通過Singleton.getInstance來獲取Singleton的實例,使用者必須知道Singleton類是一個單例類,這增加了代碼的“不透明性”,通過Singleton.getInstance獲取對象的方式也與一般的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,會報錯
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')
現在我們實現了一個透明的單例類的編寫,但仍有一些問題
CreateDiv類中實際上有兩個功能:創建對象和執行初始化init方法、保證只有一個對象。不符合單一職責原則。
當我們需要取消單例,變成一個正常的構造函數時,修改代碼會帶來一些不必要的麻煩
3,透明單例改-代理模式
// 用代理實現代理模式
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)
現在,負責管理單例的的邏輯在ProxySingletonCreateDiv中實現,CreateDiv就是一個普通的類,美滋滋
4,惰性單例
惰性單例指的是在需要的時候才創建對象實例。惰性單例是單例模式的重點。
在javaScript中,基於類的單例模式並不適用,需要轉變思路
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'
}
缺點:loginLayer在頁面進來之後就直接執行了,如果用戶不需要這個彈框,很浪費
4.2,彈框功能節約版
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'
}
雖然節約了,但是每次點擊的時候都會創建新的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'
}
確實實現了單例的功能,但是彈框的創建和管理(if(!div) return div這段控制返回的代碼)都在createLoginLayer中實現,違反了單一職責原則
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!