一、是什麼
單例模式(Singleton Pattern):建立型模式,提供了一種建立物件的最佳方式,這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立
在應用程式執行期間,單例模式只會在全域性作用域下建立一次例項物件,讓所有需要呼叫的地方都共享這一單例物件,如下圖所示:
從定義上來看,全域性變數好像就是單例模式,但是一般情況我們不認為全域性變數是一個單例模式,原因是:
- 全域性命名汙染
- 不易維護,容易被重寫覆蓋
二、實現
在javascript
中,實現一個單例模式可以用一個變數來標誌當前的類已經建立過物件,如果下次獲取當前類的例項時,直接返回之前建立的物件即可,如下:
// 定義一個類 function Singleton(name) { this.name = name; this.instance = null; } // 原型擴充套件類的一個方法getName() Singleton.prototype.getName = function() { console.log(this.name) }; // 獲取類的例項 Singleton.getInstance = function(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance }; // 獲取物件1 const a = Singleton.getInstance('a'); // 獲取物件2 const b = Singleton.getInstance('b'); // 進行比較 console.log(a === b);
使用閉包也能夠實現,如下:
function Singleton(name) { this.name = name; } // 原型擴充套件類的一個方法getName() Singleton.prototype.getName = function() { console.log(this.name) }; // 獲取類的例項 Singleton.getInstance = (function() { var instance = null; return function(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance } })(); // 獲取物件1 const a = Singleton.getInstance('a'); // 獲取物件2 const b = Singleton.getInstance('b'); // 進行比較 console.log(a === b);
也可以將上述的方法稍作修改,變成建構函式的形式,如下:
// 單例建構函式 function CreateSingleton (name) { this.name = name; this.getName(); }; // 獲取例項的名字 CreateSingleton.prototype.getName = function() { console.log(this.name) }; // 單例物件 const Singleton = (function(){ var instance; return function (name) { if(!instance) { instance = new CreateSingleton(name); } return instance; } })(); // 建立例項物件1 const a = new Singleton('a'); // 建立例項物件2 const b = new Singleton('b'); console.log(a===b); // true
三、使用場景
在前端中,很多情況都是用到單例模式,例如頁面存在一個模態框的時候,只有使用者點選的時候才會建立,而不是載入完成之後再建立彈窗和隱藏,並且保證彈窗全域性只有一個
可以先建立一個通常的獲取物件的方法,如下:
const getSingle = function( fn ){ let result; return function(){ return result || ( result = fn .apply(this, arguments ) ); } };
建立彈窗的程式碼如下:
const createLoginLayer = function(){ var div = document.createElement( 'div' ); div.innerHTML = '我是浮窗'; div.style.display = 'none'; document.body.appendChild( div ); return div; }; const createSingleLoginLayer = getSingle( createLoginLayer ); document.getElementById( 'loginBtn' ).onclick = function(){ var loginLayer = createSingleLoginLayer(); loginLayer.style.display = 'block'; };
上述這種實現稱為惰性單例,意圖解決需要時才建立類例項物件
並且Vuex
、redux
全域性態管理庫也應用單例模式的思想,如下圖:
現在很多第三方庫都是單例模式,多次引用只會使用同一個物件,如jquery
、lodash
、moment
...
參考文獻
- https://zh.wikipedia.org/zh-hans/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F
- https://www.runoob.com/design-pattern/singleton-pattern.html
- https://juejin.cn/post/6844903874210299912#heading-5
如果對您有所幫助,歡迎您點個關注,我會定時更新技術文件,大家一起討論學習,一起進步。