JS中的單例模式(ES5/ES6/Nodejs)

原文博客地址,歡迎討論,starjavascript

偶然間看到有人使用ES6class語法實現了一個比較好的單例模式,就想着結合所接觸到的和網上一些討論的實際例子來看看在javascript中單例是怎麼玩耍的,怎麼應用的。java

ES3/ES5 中的單例模式

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 語法糖實現

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 模塊化實現單例子

其實這裏說實現不是很準確,只能說目前nodejsES6的模塊化中的每一個模塊其實就是單例的。下面咱們來先看一下代碼:設計模式

class A {
  doSomething() { ... }
}
modules.export = new A() // 這裏直接將對象生成,而後導出
複製代碼

由於nodejsES6中每一個模塊的代碼只會被加載一遍,第二次或者第三次等等,就會從cache裏面去查找,是否已經加載過,就直接使用了。閉包

  • 首先咱們建立一個a.js,在裏面隨便打印一句話。
    a.js
  • 打開node,導入這個文件。
    require
  • 咱們查看一下module
    module
    能夠看到這個模塊已經被存儲下來了,以後回去就會根據id(模塊的路徑)判斷,是否須要執行該模塊的代碼。

一些應用場景

  • 網頁上的loading,整個網頁能夠只建立一個實例,根據傳入不一樣的參數去渲染不一樣的樣式或者行爲,全局通用。
  • nodejs裏面的數據庫連接實例,訪問一次建立一次連接是很消耗資源的,因此也是全局的查詢操做都是統一使用一個實例。

總結

單例模式仍是很是簡單,也很實用。目前還能夠實用ES6的代理去修改對象的建立來達到單例。這些只是實現方法,咱們須要多多思考,那些場景這些設計模式來達到代碼的可擴展性和可複用性等。模塊化

相關文章
相關標籤/搜索