從ES6重新認識JavaScript設計模式

1. 什麼是單例模式?

單例模式是一種十分常用但卻相對而言比較簡單的單例模式。它是指在一個類只能有一個實例,即使多次實例化該類,也只返回第一次實例化後的實例對象。單例模式不僅能減少不必要的內存開銷, 並且在減少全局的函數和變量衝突也具有重要的意義。

1.1 最簡單的單例模式

就算你對於單例模式的概念還比較模糊,但是我相信你肯定已經使用過單例模式了。我們來看一下下面的一段代碼:

從ES6重新認識JavaScript設計模式

1.2 惰性單例

採用對象字面量創建單例只能適用於簡單的應用場景,一旦該對象十分複雜,那麼創建對象本身就需要一定的耗時,且該對象可能需要有一些私有變量和私有方法。此時使用對象字面創建單例就不再行得通了,我們還是需要採用構造函數的方式實例化對象。下面就是使用立即執行函數和構造函數的方式改造上面的timeTool工具庫。

從ES6重新認識JavaScript設計模式

上面的timeTool實際上是一個函數,_instance作為實例對象最開始賦值為null,init函數是其構造函數,用於實例化對象,立即執行函數返回的是匿名函數用於判斷實例是否創建,只有當調用timeTool()時進行實例的實例化,這就是惰性單例的應用,不在js加載時就進行實例化創建, 而是在需要的時候再進行單例的創建。 如果再次調用, 那麼返回的永遠是第一次實例化後的實例對象。

從ES6重新認識JavaScript設計模式

2. 單例模式的應用場景

2.1 命名空間

一個項目常常不只一個程序員進行開發和維護, 然後一個程序員很難去弄清楚另一個程序員暴露在的項目中的全局變量和方法。如果將變量和方法都暴露在全局中, 變量衝突是在所難免的。就想下面的故事一樣:

從ES6重新認識JavaScript設計模式

從ES6重新認識JavaScript設計模式

2.2 管理模塊

上面說到的timeTool對象是一個只用來處理時間的工具庫,但是實際開發過程中的庫可能會有多種多樣的功能,例如處理ajax請求,操作dom或者處理事件。這個時候單例模式還可以用來管理代碼庫中的各個模塊,例如下面的代碼所示。

從ES6重新認識JavaScript設計模式

上面的代碼庫中有ajax,dom和event三個模塊,用同一個命名空間devA來管理。在進行相應操作的時候,只需要devA.ajax.get()進行調用即可。這樣可以讓庫的功能更加清晰。

3. ES6中的單例模式

3.1 ES6創建對象

ES6中創建對象時引入了class和constructor用來創建對象。下面我們來使用ES6的語法實例化蘋果公司

從ES6重新認識JavaScript設計模式

從ES6重新認識JavaScript設計模式

點擊我的頭像,關注我,私信回覆:【學習資料】就可以領取小編給大家分享的學習

3.2 ES6中創建單例模式

蘋果這麼偉大的公司明顯有且只有一個, 就是喬爺爺創建的那個, 哪能容別人進行復制?所以appleCompany應該是一個單例, 現在我們使用ES6的語法將constructor改寫為單例模式的構造器。

從ES6重新認識JavaScript設計模式

3.3 ES6的靜態方法優化代碼

ES6中提供了為class提供了static關鍵字定義靜態方法, 我們可以將constructor中判斷是否實例化的邏輯放入一個靜態方法getInstance中,調用該靜態方法獲取實例, constructor中只包需含實例化所需的代碼,這樣能增強代碼的可讀性、結構更加優化。

4. 單例模式的項目實戰應用

4.1 實現登陸彈框

登陸彈框在項目中是一個比較經典的單例模式,因為對於大部分網站不需要用戶必須登陸才能瀏覽,所以登陸操作的彈框可以在用戶點擊登陸按鈕後再進行創建。而且登陸框永遠只有一個,不會出現多個登陸彈框的情況,也就意味著再次點擊登陸按鈕後返回的永遠是一個登錄框的實例。

現在來梳理一下我登陸彈框的流程,在來進行代碼的實現:

給頂部導航模塊的登陸按鈕註冊點擊事件

登陸按鈕點擊後JS動態創建遮罩層和登陸彈框

遮罩層和登陸彈框插入到頁面中

給登陸框中的關閉按鈕註冊事件, 用於關閉遮罩層和彈框

給登陸框中的輸入框添加校驗(此步驟略)

4.1.1 給頁面添加頂部導航欄的HTML代碼

從ES6重新認識JavaScript設計模式

4.1.2 使用ES6的語法創建Login類

lass Login {

//構造器

constructor() {

this.init();

}

//初始化方法

init() {

//新建div

let mask = document.createElement('div');

//添加樣式

mask.classList.add('mask-layer');

//添加模板字符串

mask.innerHTML =

`

`;

//插入元素

document.body.insertBefore(mask, document.body.childNodes[0]);

//註冊關閉登錄框事件

Login.addCloseLoginEvent();

}

//靜態方法: 獲取元素

static getLoginDom(cls) {

return document.querySelector(cls);

}

//靜態方法: 註冊關閉登錄框事件

static addCloseLoginEvent() {

this.getLoginDom('.close-btn').addEventListener('click', () => {

//給遮罩層添加style, 用於隱藏遮罩層

this.getLoginDom('.mask-layer').style = "display: none";

})

}

//靜態方法: 獲取實例(單例)

static getInstance() {

if(!this.instance) {

this.instance = new Login();

} else {

//移除遮罩層style, 用於顯示遮罩層

this.getLoginDom('.mask-layer').removeAttribute('style');

}

return this.instance;

}

}

單例模式雖然簡單,但是在項目中的應用場景卻是相當多的,單例模式的核心是確保只有一個實例, 並提供全局訪問。就像我們只需要一個瀏覽器的window對象, jQuery的$對象而不再需要第二個。 由於JavaScript代碼書寫方式十分靈活, 這也導致瞭如果沒有嚴格的規範的情況下,大型的項目中JavaScript不利於多人協同開發, 使用單例模式進行命名空間,管理模塊是一個很好的開發習慣,能夠有效的解決協同開發變量衝突的問題。靈活使用單例模式,也能夠減少不必要的內存開銷,提高用於體驗。


分享到:


相關文章: