一、是什么
單例模式(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
如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。