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

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

realdennis
Apr 30 · 3 min read

依照上述命題我們可以揣測,最終結果應該會是這個 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 存下來的實例能不被修改。

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

realdennis

Written by

程式人 / 前端 / 寫文章 https://github.com/realdennis

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade