單例模式
是一種常見的設計模式,在應用這個模式時,必須保證單例對象的類隻有一個執行個體存在;這樣全局擁有一個對象,有利于我們進行系統調整。
把描述同一件事物的屬性和方法放在同一段堆記憶體中,起到分組的作用,防止沖突;這樣不同僚物間即使屬性名一樣也不會發生沖突,這種分組的編寫代碼模式叫做單例模式;在單例模式中把對象名叫做命名空間。
單例模式是一種項目開發中經常使用的模式,可以使用單例模式進行子產品化開發。
應用場景
當我們需要多人合作完成一個項目,但是有一些操作是同樣的操作時(例如:點選按鈕顯示加載的遮罩層;例如:送出表單時的驗證都是一樣的),這個時候我們就需要單例模式。
缺點
我們可以通過操作直接對象中的屬性改變了原有的值。
執行個體
有這樣一個常見的需求,點選某個按鈕的時候需要在頁面彈出一個遮罩層。比如web.qq.com點選登入的時候.
這個生成灰色背景遮罩層的代碼是很好寫的.
var createMask = function(){
return document.body.appendChild( document.createElement('div') );
}
$( 'button' ).click( function(){
Var mask = createMask();
mask.show();
})
複制
問題是, 這個遮罩層是全局唯一的, 那麼每次調用createMask都會建立一個新的div, 雖然可以在隐藏遮罩層的把它remove掉. 但顯然這樣做不合理.
再看下第二種方案, 在頁面的一開始就建立好這個div. 然後用一個變量引用它.
var mask = document.body.appendChild( document.createElement( 'div' ) );
$( 'button' ).click( function(){
mask.show();
} )
複制
這樣确實在頁面隻會建立一個遮罩層div, 但是另外一個問題随之而來, 也許我們永遠都不需要這個遮罩層, 那又浪費掉一個div, 對dom節點的任何操作都應該非常吝啬.
如果可以借助一個變量. 來判斷是否已經建立過div呢?
var mask;
var createMask = function(){
if ( mask ) return mask;
else{
mask = document,body.appendChild( document.createElement('div') );
return mask;
}
}
複制
看起來不錯, 到這裡的确完成了一個産生單列對象的函數. 我們再仔細看這段代碼有什麼不妥.
首先這個函數是存在一定副作用的, 函數體内改變了外界變量mask的引用, 在多人協作的項目中, createMask是個不安全的函數. 另一方面, mask這個全局變量并不是非需不可. 再來改進一下.
var createMask = function(){
var mask;
return function(){
return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
}
}()
複制
用了個簡單的閉包把變量mask包起來, 至少對于createMask函數來講, 它是封閉的