此文僅記錄本人閱讀《JavaScript設計模式與開發實踐》這個本時的感覺,感謝做者曾探寫出這麼好的一本書。若有冒犯,若有錯誤,請聯繫本人:luogao_lg@sina.com處理。javascript
這一章讓我知道了單例模式的核心就是:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。但在JavaScript中單例模式有別的區別於傳統面嚮對象語言的應用,惰性單例模式在實際的開發中有不少用途,例如提升頁面性能,避免沒必要要的DOM操做等。html
書中有舉出一個實際場景,當咱們點擊登錄按鈕時,頁面中可能會出現一個彈框,而這個彈框是惟一的,不管點多少次登錄按鈕,彈框只會被建立一次,那麼這種狀況下就適合用單例模式來建立彈框。java
如下代碼來自書中編程
var CreateDiv = (function(html) {
var instance
var CreateDiv = function() {
if (instance) {
return instance
}
this.html = html
this.init()
return instance = this
}
CreateDiv.prototype.init = function() {
var div = document.createElement('div')
div.innerHTML = this.html
document.appendChild(div)
}
return CreateDiv
})()
複製代碼
以上代碼經過自執行函數和閉包將instance封裝起來。而且返回了真正的
Singleton
構造方法。設計模式
經過觀察上面代碼發現CreateDiv
裏執行了兩個操做:閉包
init
方法。若是某天咱們須要用這個方法向頁面中建立更多的元素。那咱們必需要改寫CreateDiv
,若是咱們結合「單一職責原則」,咱們就知道要去把保證只有一個對象這個操做從CreateDiv
抽離出來。這個目的能夠經過代理來實現。app
首先咱們把上面代碼中的CreateDiv
方法改寫成一個只負責建立DIV的類函數
var CreateDiv = function(html) {
this.html = html
this.init()
}
CreateDiv.prototype.init = function() {
var div = document.createElement('div')
div.innerHTML = this.html
document.appendChild(div)
}
複製代碼
接下來引入代理類性能
var ProxysingletonCreateDiv = (function() {
var instance
return function(html) {
if (!instance) {
instance = new CreateDiv(html)
}
return instance
}
})()
var a = new ProxysingletonCreateDiv('test1')
var b = new ProxysingletonCreateDiv('test2')
alert(a === b) // true
複製代碼
至此利用代理類也實現了一個單例模式。但目前咱們討論的單例模式跟接近傳統面嚮對象語言中的實現。接下來咱們來了解一下JavaScript中的單例模式。網站
瞭解了單例模式的一些實現方法以後。咱們能夠來看看惰性單例的實現,這種實現方式在JavaScript的實際編程中是很實用的。
惰性單例是指在須要的時候才建立對象實例,而不是像以前的代碼那樣,利用自執行函數在代碼執行時就把對象實例建立。
好比最開始就提到,當打開一個網站時,須要登陸,但登錄的彈窗只會在點擊登錄按鈕時出現,甚至有的網站不須要登陸就能直接瀏覽。這時咱們並不須要在頁面加載時就去建立一個彈窗。咱們大可在須要用的時候去建立。
<html>
<body>
<button id="loginBtn">登陸</button>
</body>
<script> var createLoginLayer = (function() { var div return function() { if (!div) { var div = document.createElement('div') div.innerHTML = '我是登陸彈窗' div.style.display = 'none' document.appendChild(div) } return div } })() document.getElementById('loginBtn').onclick = function() { var loginLayer = createLoginLayer() loginLayer.style.display = 'block' } </script>
</html>
複製代碼
以上咱們實現了一個單例模式的彈窗。可是咱們仍是能夠把其中的控制只有一個對象的操做抽離出來,讓咱們來實現一個通用的惰性單例。
通用惰性單例的實現就是要抽離全部單例模式都要實現的——控制只有一個對象。那麼咱們來看看控制只有一個對象的操做抽象出來是個什麼樣子:
var obj
if (!obj) {
obj = xxx
}
複製代碼
因而就能夠把這個操做的邏輯封裝到一個getSingle
函數中,而後把要執行的函數看成參數傳入進去:
var getSingle = function(fn) {
var result
return function() {
result || (result = fn.apply(this, arguments))
}
}
複製代碼
這樣咱們上面寫的建立彈窗的方法就能夠徹底抽離出來:
var createLoginLayer = function() {
var div = document.createElement('div')
div.innerHTML = '我是登陸彈窗'
div.style.display = 'none'
document.appendChild(div)
return div
}
var createSingleLoginLayer = getsingle(createLoginLayer)
document.getElementById('loginBtn').onclick = function() {
var loginLayer = createSingleLoginLayer()
loginLayer.style.display = 'block'
}
複製代碼
至此咱們實現了一個getSingle
函數來幫咱們實現只有一個實例對象的目的,而且將實例對象要作的指責獨立出來,兩個方法互不打擾。
原文出自 Roy's Blog
《JavaScript設計模式與開發實踐》—— 曾探