一、是什麼 單例模式(Singleton Pattern):創建型模式,提供了一種創建對象的最佳方式,這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建 在應用程式運行期間,單例模式只會在全局作用域下創建一次實例對象,讓所有需要調用的地方都共用這一單例對象,如下圖所示: ...
一、是什麼
單例模式(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
如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。