單例模式的定義是:保證一個類僅有一個一個實例,並提供一個訪問它的全局訪問點。html
單例模式能在合適的時候建立對象,而且建立惟一的一個。
代碼接近於生活,頗有意思。好比一個網站的登陸,點擊登陸後彈出一個登陸彈框,即便再次點擊,也不會再出現一個相同的彈框。又或者一個音樂播放程序,若是用戶打開了一個音樂,又想打開一個音樂,那麼以前的播放界面就會自動關閉,切換到當前的播放界面。這些都是單例模式的應用場景。
要實現一個單例模式,一個經典的方式是建立一個類,類中又一個方法能建立該類的實例對象,還有一個標記,記錄是否已經創了過了實例對象。若是對象已經存在,就返回第一次實例化對象的引用。es6
var Singleton = function(name) { this.name = name; //一個標記,用來判斷是否已將建立了該類的實例 this.instance = null; } // 提供了一個靜態方法,用戶能夠直接在類上調用 Singleton.getInstance = function(name) { // 沒有實例化的時候建立一個該類的實例 if(!this.instance) { this.instance = new Singleton(name); } // 已經實例化了,返回第一次實例化對象的引用 return this.instance; }
用戶能夠經過一個廣爲人知的接口,對該實例進行訪問。
咱們嘗試對該對象進行兩次實例化,觀察兩次實例化結果是否指向同一個對象。app
var a = Singleton.getInstance('sven1'); var b = Singleton.getInstance('sven2'); // 指向的是惟一實例化的對象 console.log(a === b);
返回結果是:true。說明a、b之間是引用關係。函數
建立Singleton類。class關鍵字和靜態函數都是es6新增的。網站
class Singleton { constructor(name) { this.name = name; this.instance = null; } // 構造一個廣爲人知的接口,供用戶對該類進行實例化 static getInstance(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance; } }
咱們用一個生活中常見的一個場景來講明單例模式的應用。
任意一個網站,點擊登陸按鈕,只會彈出有且僅有一個登陸框,即便後面再點擊登陸按鈕,也不會再彈出多一個彈框。這就是單例模式的典型應用。接下來咱們實現它。爲了注重單例模式的展現,咱們把登陸框簡化吧😜
在頁面上設置一個按鈕ui
<button id="loginBtn">登陸</button>
爲這個按鈕添加點擊事件this
const btn = document.getElementById('loginBtn'); btn.addEventListener('click', function() { loginLayer.getInstance(); }, false);
咱們先給一個初始化方法init,在點擊按鈕以後,在頁面上添加一個框框(權當登陸框了)es5
init() { var div = document.createElement('div'); div.classList.add('login-layer'); div.innerHTML = "我是登陸浮窗"; document.body.appendChild(div); }
那麼接下來要用單例模式實現,點擊按鈕出現有且僅有一個浮窗,方法就是在構造函數中建立一個標記,第一次點擊時建立一個浮窗,用改變標記的狀態,再次點擊按鈕時,根據標記的狀態判斷是否要再建立一個浮窗。
上源碼:code
class loginLayer { constructor() { // 判斷頁面是否已有浮窗的標記 this.instance = null; this.init(); } init() { var div = document.createElement('div'); div.classList.add('login-layer'); div.innerHTML = "我是登陸浮窗"; document.body.appendChild(div); } // 靜態方法做爲廣爲人知的接口 static getInstance() { // 根據標記的狀態判斷是否要再添加浮窗,若是標記不爲空就建立一個浮窗 if(!this.instance) { this.instance = new loginLayer(); } return this.instance; } }
固然不要忘記爲浮窗添加一個樣式,讓浮窗顯示啦htm
.login-layer { width: 200px; height: 200px; background-color: rgba(0, 0, 0, .6); text-align: center; line-height: 200px; display: inline-block; }
最後奉上該實例的源碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>單例實現登陸彈窗</title> <style> .login-layer { width: 200px; height: 200px; background-color: rgba(0, 0, 0, .6); text-align: center; line-height: 200px; display: inline-block; } </style> </head> <body> <button id="loginBtn">登陸</button> <script> const btn = document.getElementById('loginBtn'); btn.addEventListener('click', function() { loginLayer.getInstance(); }, false); class loginLayer { constructor() { this.instance = null; this.init(); } init() { var div = document.createElement('div'); div.classList.add('login-layer'); div.innerHTML = "我是登陸浮窗"; document.body.appendChild(div); } static getInstance() { if(!this.instance) { this.instance = new loginLayer(); } return this.instance; } } </script> </body> </html>