單例模式:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
在 JavaScript 開發(fā)中爱沟,有一些對(duì)象只需要一個(gè)。比如單擊登錄按鈕匆背,頁(yè)面會(huì)出現(xiàn)登錄對(duì)話框呼伸,并且是唯一的。
無論單擊多少次按鈕,登錄對(duì)話框都只會(huì)被創(chuàng)建一次括享,那么這個(gè)登錄對(duì)話框就比較適合用單例模式創(chuàng)建搂根。
1. 單例模式的實(shí)現(xiàn)(不透明)
實(shí)現(xiàn)思路:通過一個(gè)變量標(biāo)記當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建實(shí)例,如果是則下一次獲取該類的實(shí)例铃辖,否則進(jìn)行新建剩愧。
const Singleton = function (name) {
this.name = name;
};
Singleton.prototype.getName = function () {
return this.name;
};
Singleton.getInstance = (function (name) {
let instance = null;
return function () {
if (!instance) {
instance = new Singleton(name);
}
return instance;
};
})();
const singleA = Singleton.getInstance("sven1");
const singleB = Singleton.getInstance("sven2");
console.log(singleA === singleB); // true
弊端:此方法通過 getInstance
可以保證只會(huì)創(chuàng)建一個(gè)實(shí)例,但是無法保證通過 new Singleton
這個(gè)方式創(chuàng)建其他的實(shí)例娇斩,所以意義不大仁卷。
2. 透明的單例模式
實(shí)現(xiàn)思路:通過必報(bào)和自執(zhí)行匿名函數(shù),可以把 instance
封裝起來犬第,不被外界訪問得到锦积。
const Singleton = (function () {
let instance = null;
function CreateSingleton(name) {
this.name = name;
}
CreateSingleton.prototype.getName = function () {
return this.name;
};
return function (name) {
if (!instance) {
instance = new CreateSingleton(name);
}
return instance;
};
})();
const singleA = new Singleton("sven1");
const singleB = new Singleton("sven2");
console.log(singleA === singleB); // true
弊端:通過匿名函數(shù)和閉包創(chuàng)建,增加了程序的復(fù)雜度歉嗓,不易理解丰介。
3. 代理實(shí)現(xiàn)單例模式
通過代理類,可以讓 Singleton
變?yōu)橐粋€(gè)普通的函數(shù)鉴分。
function Singleton(name) {
this.name = name;
}
Singleton.prototype.getName = function () {
return this.name;
};
const ProxySingleton = (function () {
let instance = null;
return function (name) {
if (!instance) {
instance = new Singleton(name);
}
return instance;
};
})();
const singleA = new ProxySingleton("sven1");
const singleB = new ProxySingleton("sven2");
console.log(singleA === singleB); // true
4. 惰性單例模式
惰性單例是指在需要的時(shí)候才創(chuàng)建對(duì)象實(shí)例哮幢。
// 將函數(shù)作為一個(gè)參數(shù)傳遞
const getSingle = function (fn) {
let result;
return function () {
// 通過apply的方式收集參數(shù)并執(zhí)行傳入的參數(shù)將結(jié)果返回
return result || (result = fn.apply(this, arguments));
};
};
這種方式最大的優(yōu)點(diǎn)就是緩存了需要的結(jié)果,并且可以在需要的時(shí)候去調(diào)用冠场,符合封裝的單一職責(zé)家浇。