上次總結了設計模式中的module模式,可能沒有真真正正的使用在場景中,發現效果並很差,想要使用起來卻不那麼駕輕就熟,html
因此此次我打算換一種方式~~從簡單的場景中來看單例模式,設計模式
由於JavaScript很是靈活,因此在使用設計模式的時候也帶來了很強的靈活性,實現單例的方法也有不少,那就須要咱們把握住單例模式的核心。閉包
單例模式介紹:dom
單例模式是保證一個類只有一個實例,實現的方法通常是先判斷實例存在與否,若是存在直接返回,若是不存在就建立了再返回,這就確保了一個類只有一個實例對象。模塊化
在JavaScript裏,單例做爲一個命名空間提供者,從全局命名空間裏提供一個惟一的訪問點來訪問該對象函數
做用:測試
一、模塊間通訊this
二、系統中某各種的對象只能存在一個spa
三、保護本身的屬性和方法,保證了全部的對象訪問的都是同一個實例設計
注意事項:
一、注意this的使用
二、閉包容易形成內存泄露,不須要的儘快處理等待回收
咱們先來實現一個標準的單例模式:
一、若是實例存在就返回,實例不存在就建立新實例;
二、從全局命名空間中隔離出代碼,從而爲函數提供單一訪問點:
var mySingleton = (function () { // 實例保持Singleton的一個引用 let instance; // Singleton // 私有方法和變量 function init() { function privateMethod() { console.log('I am private'); } const privateVariable = ' I am also private '; const privateRandomNumber = Math.random(); // 公有方法和變量 return { publicMethod:function(){ console.log('I am public'); }, getRandomNumber:function(){ return privateRandomNumber; } } } // 獲取Singleton實例,若是存在就返回,不存在就建立新實例 return { getInstance:function(){ if(!instance){ instance = init(); } return instance; } } })(); // 測試 const singleA = mySingleton.getInstance(); const singleB = mySingleton.getInstance();
console.log( singleA.getRandomNumber() === singleB.getRandomNumber()); // true console.log(singleA.publicMethod()) // I am public
下面寫一個咱們在場景中常常使用的一種簡單的非標準的單例模式類型,
場景一:使用簡單的單例模式實現一個可編輯表格
html
<table class="table table-bordered" id="js-table-test">
<tr>
<td>編號</td>
<td>姓名</td>
</tr>
<tr>
<td>1</td>
<td>okaychen</td>
</tr>
<tr>
<td>2</td>
<td>StackOverflowChen</td>
</tr>
</table>
沒使用單例模式以前,咱們可能會這樣處理:
$("#js-table-test td").click(function (argument) { var m = $(this).html(); var s = "<input type='text' value='" + m + "' />"; $(this).html(s); }) $("#js-table-test td").on('keyup','input',function(e){ e.stopPropagation(); var me = $(this); if(e.keyCode==13){ me.val(); } })
那麼就讓咱們對比一下使用單例的代碼 思路>>
一、使用自執行函數傳遞參數$,減小查詢次數
二、使用簡單的單例模式,爲以後修改或者模塊化打基礎
提供單一訪問點init,經過datas共享數據,render封裝對應的元素,bind來綁定事件,_do來規範私有事件;
(function ($) { // 命名空間 var index = { init: function () { // 入口 var me = this; me.render(); me.bind(); }, datas: { // 共享數據 num: 1 }, render: function () { // 封裝對應的元素 var me = this; me.test = $('#js-table-test td'); }, bind: function () { // 綁定事件 var me = this; me.test.on('click', $.proxy(me['_do'], this)); }, _do: function (e) { // 私有事件 var me = this; var m = $(e.target).text(); var s = "<input type='text' value='" + m + "' />"; $(e.target).html(s); console.log(me.datas.num ++) } } index.init(); })(jQuery);