淺析 JS 設計模式之:單例模式

良好的設計模式能夠顯著提升代碼的可讀性,下降複雜度和維護成本。筆者打算經過幾篇文章通俗地講一講常見的或者實用的設計模式。編程

今天先從最簡單的一個入手:單例模式。設計模式

文中的示例代碼會使用 ES6 語法,儘可能簡化沒必要要的細節

概念

單例模式(Singleton)屬於建立型的設計模式,它限制咱們只能建立單一對象或者某個類的單一實例。緩存

一般狀況下,使用該模式是爲了控制整個應用程序的狀態。在平常的開發中,咱們遇到的單例模式可能有:Vuex 中的 StoreVue 的根實例任何導出單個對象的 ES6 模塊等。模塊化

字面量寫法

最簡單的單例其實就像下面這樣:函數

const cat = {
    name: 'mi',
    age: 4
}

瞭解 const 語法的小夥伴都知道,這隻喵是不能被從新賦值的,可是它裏面的屬性實際上是可變的。this

若是想要一個不可變的單例對象:spa

const cat = {
    name: 'mi',
    age: 4
}

Object.freeze(cat);

這樣就不能新增或修改這隻喵上的任何屬性,它變成了 冰凍喵~ 設計

若是是在模塊中使用,上面的寫法並不會污染全局做用域,可是直接生成一個固定的對象缺乏了一些靈活性。code

經常使用寫法

相對而言,使用類或工廠方法來實現單例更加經常使用。假設咱們有一個叫做 Logger 的類,它具備和 Console 相同的 API。對象

類單例

類的單例寫法很是經常使用,若是咱們想要這麼使用它:

const logger = new Logger();
logger.log('msg');

// 這裏大概寫了 1000 行代碼

const logger2 = new Logger();
logger.log('new msg');

logger === logger2; // true

即儘管 new 了屢次 Logger,它返回的都是同一個實例。

下面直接看最實用的實現方式:

class Logger {
    constructor () {
        if (!Logger._singleton) {
            Logger._singleton = this;
        }
        return Logger._singleton;
    }
    
    log (...args) {
        console.log(...args);
    }
}

export default Logger;

上面的方式將單例對象存儲在了構造器上,這樣的話無論 new Logger 多少次,返回的都是同一個 Logger 實例了。

這裏有一個細節須要注意,即 new 關鍵字後面的構造函數若是顯式返回一個對象,new 表達式就會返回該對象。

具體可參見 《你不知道的 JavaScript (上卷)》中的 new 綁定 相關章節。

工廠單例

若是不喜歡用 new 關鍵字,可使用工廠方法返回單例對象。

let logger = null

class Logger {
    log (...args) {
        console.log(...args);
    }
}

function createLogger() {
    if (!logger) {
        logger = new Logger();
    }
    return logger;
}

export default createLogger;

上面的代碼至關於在模塊內部緩存了 logger 實例,而後導出了一個工廠方法。這種寫法在模塊化代碼中比較常見,工廠方法也能夠接收參數用來初始化單例對象。

今天的內容比較好理解,其中的單例寫法也是筆者經常使用的方法。

下一篇咱們再具體講講工廠模式的應用~

參考內容


本文首發於公衆號:碼力全開(codingonfire)

本文隨意轉載哈,註明原文連接便可,公號文章轉載聯繫我開白名單就好~

codingonfire.jpg

相關文章
相關標籤/搜索