原文博客地址,歡迎討論,starjavascript
偶然間看到有人使用ES6
的class
語法實現了一個比較好的單例模式,就想着結合所接觸到的和網上一些討論的實際例子來看看在javascript
中單例是怎麼玩耍的,怎麼應用的。java
在ES3/ES5
中,尚未class
這樣的語法,以前最先接觸設計模式的時候,通常網上的教程都是以java
來解釋的,由於做爲面向對象的語言確實好像能直觀的去解釋這些設計模式。 好比,單例模式,就是保證一個類只有一個實例,實現的方法通常是先判斷實例存在與否,若是存在直接返回,若是不存在就建立了再返回,這就確保了一個類只有一個實例對象。node
在javascript
中,是沒有類這個東西的,全都是對象,因此在其中實現單例通常是使用一個子執行函數返回一個對象,這個對象去有個方法去獲取instance
, 在獲取的時候進行是否存在的判斷。以下:git
var Single = (function(){
var instance;
/* * 這裏面還能夠定義一些私有的方法,主要是用到了閉包 */
function get() {
/* * 這裏返回的就是最後被使用到的對象 */
return {
doSomething: function () {
console.log("AAA")
}
}
}
return {
getInstance () {
return instance || (instance = get()) // 若是instance 變量是有值的就直接返回,若是是沒有值的就調用生成對象返回並賦值給instance
}
}
})()
var instance1 = Single.getInstance()
var instance2 = Single.getInstance()
console.log(instance1 === instance2) // true
複製代碼
在ES3/ES5
通常都會使用如上組織形式去實現單例模式,接下來咱們看一下在ES6
以後的場景。es6
ES6
引入class
關鍵字,一套很簡潔用來實現js
裏面構造函數的語法糖。若是對class
的用法還不是很熟悉的能夠點擊阮老師的es6入門 來學習一下。先看代碼:github
const single = 'single' // 這裏使用symbol會好一點
class A {
static get instace () {
if (this[single]) { // 因爲是靜態函數,這裏的this指的是A,並非 new A() 產生的對象哦。
return this.single
}
return this[single] = new this() // 若是沒有值就new 構造函數
}
constructor() {
const sourceClass = this.constructor // 獲取構造函數對象
if (!sourceClass[single]) { // 判斷對象上面是否已經有了單例
sourceClass[single] = this // 這裏的this指的是已經構造好的對象,空對象,只是constructor指向A
}
return sourceClass[single] // 若是已經存在則直接返回
}
}
複製代碼
上面這份代碼仍是須要點較深ES6
的知識才能看明白的,這個」類「裏面有兩個方法來產生實例。數據庫
this
來指向A
這個構造函數(構造函數也是對象),我代碼上也作了註釋。關鍵點就是,根據指定key
來掛載這個實例,可是封裝性更好了一點。其實這裏說實現不是很準確,只能說目前nodejs
和ES6
的模塊化中的每一個模塊其實就是單例的。下面咱們來先看一下代碼:設計模式
class A {
doSomething() { ... }
}
modules.export = new A() // 這裏直接將對象生成,而後導出
複製代碼
由於nodejs
和ES6
中每一個模塊的代碼只會被加載一遍,第二次或者第三次等等,就會從cache
裏面去查找,是否已經加載過,就直接使用了。閉包
a.js
,在裏面隨便打印一句話。
node
,導入這個文件。
module
loading
,整個網頁能夠只建立一個實例,根據傳入不一樣的參數去渲染不一樣的樣式或者行爲,全局通用。nodejs
裏面的數據庫連接實例,訪問一次建立一次連接是很消耗資源的,因此也是全局的查詢操做都是統一使用一個實例。單例模式仍是很是簡單,也很實用。目前還能夠實用ES6
的代理去修改對象的建立來達到單例。這些只是實現方法,咱們須要多多思考,那些場景這些設計模式來達到代碼的可擴展性和可複用性等。模塊化