在 JavaScript 中實現 Singleton 模式的兩個方法

Singleton 意思是特定 class 只會有一個實例,當你第二次透過同個 class 建立實例時,亦只會得到同一個實例。

realdennis
3 min readApr 30, 2019

依照上述命題我們可以揣測,最終結果應該會是這個 Singleton class 的樣子:

const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); //true
Photo by Sweet Ice Cream Photography on Unsplash

讓我們開始吧!

我們為了不發散探討的議題,這裡使用簡單的把 function 視作建構式 與 new 算子強行繫結 this,來做到仿實例化的類。

var Singleton = function (){
// constructor
this.p = 'public'
}
var instance = new Singleton();

我們希望解決命題中的「同個 class 的實例指向同個物件」,從這句話我們不難看出來有一個記憶性的行為出現,或是你可以說 memorize、cache 等等你熟悉的關鍵字

由於函數本身也是一個物件,我們可以透過在他的屬性設定一個記錄的屬性,比如像是 Singleton.cache

var Singleton = function (){
if(typeof Singleton.cache === 'object') return Singleton.cache;
// 如果有現成的就丟回去
// 沒有的話 執行第一次建構
this.p = 'public'

Singleton.cache = this;
}
var obj1 = new Singleton();
var obj2 = new Singleton();
console.log(obj1 === obj2); //true

這種做法其實已經完成了命題的要求,最終都會拿到同一個實例,不過我們仍然不滿足,這個 cache 裸露在外頭,並不是這麼安全,可能被其他程式碼複寫。

透過立即執行函數的閉包把 cache 藏起來

閉包裡的變數除非我們暴露一些特別的方法出去,否則沒有辦法直接在外部針對這個函數的閉包變數做操作。

var Singleton = (function (){
var cache;
return function(){
if(typeof cache === 'object') return cache;
this.p = 'public'
cache = this;
}
}())
var obj1 = new Singleton();
var obj2 = new Singleton();
console.log(obj1 === obj2); //true

這個 Singleton 其實被狸貓換太子換成了內部的匿名函數,並且最重要是存在一個變數 cache ,它只能被這個匿名函數取用,所以我們可以安全的把快取的實例擺在這裡。

尾聲

雖然 Singleton 是一個非常容易理解的模式,但是要建構一個穩健的模式需要考量的點可能就不只是能不能work ,而是在其他開發者在操作的時候能不能只暴露最小的權限出去,讓這個 Singleton 存下來的實例能不被修改。

我們可以從這個簡單的模式實作中明白,私有這件事是多麼重要,未來的文章有機會也會往這個方向去撰寫,探討私有變數與閉包。

--

--

No responses yet