首頁  >  文章  >  web前端  >  JavaScript設計模式系列二:單例模式

JavaScript設計模式系列二:單例模式

不言
不言原創
2018-04-02 13:55:091556瀏覽

這篇文章要跟大家分享的是JavaScript設計模式系列二:單例模式,有興趣的朋友可以看一下

單例模式

前言:本系列程式碼已上傳到GitHub位址https://github.com/HolyZheng/...

什麼是單例模式?

單例模式的定義:一個類別只有一個實例,並且可以在全域存取
什麼時候需要用到單例模式呢?其實單例模式在日常開發中的使用非常的廣泛,例如各種浮窗、像登入浮窗等,無論我們點擊多少次,都是同一個浮窗,浮窗從始至終只創建了一次。這種場景就十分適合運用單例模式。


程式碼實作

我們創建一個「最老的人」的類,很明顯,「最老的人」有且只有一個。這很符合我們單例模式的運用場景。我們先來看看完整程式碼:

var oldestMan = function (name) {
  this.name = name;
}

oldestMan.prototype.getName = function () {
  console.log(this.name);
}
//引入一个代理函数和闭包的概念
var createOldestMan = (function () {
  var instance;
  return function (name) {
      if (!instance) {
         instance = new oldestMan(name);
      }
      return instance;
  }
})();

var personA = createOldestMan("holz");
var personB = createOldestMan("Amy");
personA.getName();  //  holz
personB.getName();  //  holz

我們可以在控制台上看到即使呼叫了兩次createOldestMan並且賦了不一樣的值,但兩次getName ()輸出的都是第一次的「holz」。這就是單例模式。

程式碼看不太懂?沒關係,現在給大家一一講解。
首先我們建立了一個oldestMan類,建立了一個name屬性。然後我們透過 prototype 給它加一個getName()方法用來取得oldestMan的名字,相信到這裡大家都是懂的,然後下面一段程式碼就是重點了,也比較難理解。我們打這段程式碼單獨拿出來將一下。

//引入一个代理函数和闭包的概念
var createOldestMan = (function () {
  var instance;
  return function (name) {
      if (!instance) {
         instance = new oldestMan(name);
      }
      return instance;
  }
})();

首先,我們不用管什麼是代理函數,之所以叫它代理函數是因為它輔助我們實現單例模式的效果,這段函數第一個關鍵點是createOldestMan() 是一個立即執行函數。立即函數在宣告的時候就會立即執行,也就是在宣告createOldestMan的時候這個函數就會執行,它會宣告一個instance 變量,然後傳回一個函式給createOldestMan。 createOldestMan就相當於:

var createOldestMan = function (name) {
      if (!instance) {
         instance = new oldestMan(name);
      }
      return instance;
  }

第二個關鍵點是:這裡利用了 閉包 的概念。

閉包是什麼呢?我只需要記住當函數在定義時的語法作用域之外被調用,卻還能訪問定義時的語法作用域時,就是產生了閉包。

我們來看我們的程式碼,函數先定義了一個instance,然後再回傳一個function(name),而這個function(name)裡面用到了instance變數。在正常情況下,在立即執行函數執行之後,instance變數就會被JavaScript的垃圾回收機制回收,但是因為function(name)被返回到了外部,而function(name)隨時會被調用,隨時會訪問到instance變量,所以instance變數被保留在了記憶體中。這就產生了閉包。也就是說,function(name)被賦值給了外部的createOldestMan,在外部的語法作用域中執行,但還可以存取到定義時內部的語法作用域中的instance。

所以在 立即執行函數閉包 的作用下,instance只申請了一次,也就是只有一個instance。也就是說,我們無論執行多少次createOldestMan("..."),instance只會是第一次的那個值。所以我們就可以判斷instance是否已經被實例化了,來給instance賦值,如果instance已經被實例化,就回傳instance。這就達到了一個類別只有一個實例的效果。

通用的單例模式

我還可以改造程式碼,因為在開發中,我們可能不只一個單例,所以我們應該讓程式碼變得各個單例通用。我們該在哪裡改呢?沒錯,改代理函數。我們只需要把代理函數中的oldestMan()提取出來,改為以參數的形式傳值,不限於oldestMan()。

var singleObj;
var createSingleton = function (fn) {
  return function (text) {
    if (!singleObj) {
      singleObj = new fn (text);
    }
    return singleObj;
  }
}

這樣我們就可以把單例當作參數傳進去,用它實現不同的單例了。
完整程式碼是這樣的:

var oldestMan = function (name) {
  this.name = name;
}

oldestMan.prototype.getName = function () {
  console.log(this.name);
}

//一个通用的代理函数
var singleObj;
var createSingleton = function (fn) {
  return function (text) {
    if (!singleObj) {
    singleObj = new fn (text);
    }
    return singleObj;
  }
}

var person_1 = createSingleton(oldestMan)("holz");
var person_2 = createSingleton(oldestMan)("tom");
person_1.getName(); //holz
person_2.getName(); //holz

同樣,即使再次呼叫createSingleton並傳入不同的值,輸出的依舊是第一次的「holz」。


總結

單例模式的定義:一個類別只有一個實例,並且可以在全域存取。
適用場景:其實單例模式在日常開發中的使用非常的廣泛,例如各種浮窗、像登錄浮窗等,無論我們點擊多少次,都是同一個浮窗,浮窗從始至終只創建了一次。這種場景就十分適合運用單例模式。

相關推薦:

JavaScript設計模式系列一:工廠模式



以上是JavaScript設計模式系列二:單例模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn