單例介紹
上次總結了設計模式中的module模式,可能沒有真真正正的使用在場景中,發現效果並不好,想要使用起來卻不那么得心應手,
所以這次我打算換一種方式~~從簡單的場景中來看單例模式,
因為JavaScript非常靈活,所以在使用設計模式的時候也帶來了很強的靈活性,實現單例的方法也有很多,那就需要我們把握住單例模式的核心。
單例模式介紹:
單例模式是保證一個類只有一個實例,實現的方法一般是先判斷實例存在與否,如果存在直接返回,如果不存在就創建了再返回,這就確保了一個類只有一個實例對象。
在JavaScript里,單例作為一個命名空間提供者,從全局命名空間里提供一個唯一的訪問點來訪問該對象
作用:
1、模塊間通信
2、系統中某各類的對象只能存在一個
3、保護自己的屬性和方法,保證了所有的對象訪問的都是同一個實例
注意事項:
1、注意this的使用
2、閉包容易造成內存泄露,不需要的盡快處理等待回收
簡單場景
我們先來實現一個標准的單例模式:
1、如果實例存在就返回,實例不存在就創建新實例;
2、從全局命名空間中隔離出代碼,從而為函數提供單一訪問點:
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(); } })
那么就讓我們對比一下使用單例的代碼 思路>>
1、使用自執行函數傳遞參數$,減少查詢次數
2、使用簡單的單例模式,為之后修改或者模塊化打基礎
提供單一訪問點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);