摘要:實現代碼如下創建元素設置樣式我們發現在開發中并不會多帶帶使用遮罩層,遮罩層和彈出窗是經常結合在一起使用,前面我們提到過登陸彈窗使用單例模式實現也是最適合的。
定義
確保一個類僅有一個實例,并提供一個訪問它的全局訪問點。
單例模式使用的場景比如線程池、全局緩存等。我們所熟知的瀏覽器的window對象就是一個單例,在JavaScript開發中,對于這種只需要一個的對象,我們的實現往往使用單例。
實現單例模式 (不透明的)一般我們是這樣實現單例的,用一個變量來標志當前的類已經創建過對象,如果下次獲取當前類的實例時,直接返回之前創建的對象即可。代碼如下:
// 定義一個類 function Singleton(name) { this.name = name; this.instance = null; } // 原型擴展類的一個方法getName() Singleton.prototype.getName = function() { console.log(this.name) }; // 獲取類的實例 Singleton.getInstance = function(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance }; // 獲取對象1 var a = Singleton.getInstance("a"); // 獲取對象2 var b = Singleton.getInstance("b"); // 進行比較 console.log(a === b);
我們也可以使用閉包來實現:
function Singleton(name) { this.name = name; } // 原型擴展類的一個方法getName() Singleton.prototype.getName = function() { console.log(this.name) }; // 獲取類的實例 Singleton.getInstance = (function() { var instance = null; return function(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance } })(); // 獲取對象1 var a = Singleton.getInstance("a"); // 獲取對象2 var b = Singleton.getInstance("b"); // 進行比較 console.log(a === b);
這個單例實現獲取對象的方式經常見于新手的寫法,這種方式獲取對象雖然簡單,但是這種實現方式不透明。知道的人可以通過 Singleton.getInstance() 獲取對象,不知道的需要研究代碼的實現,這樣不好。這與我們常見的用 new 關鍵字來獲取對象有出入,實際意義不大。
實現單例模式 (透明的)var Singleton = (function(){ var instance; var CreateSingleton = function (name) { this.name = name; if(instance) { return instance; } // 打印實例名字 this.getName(); // instance = this; // return instance; return instance = this; } // 獲取實例的名字 CreateSingleton.prototype.getName = function() { console.log(this.name) } return CreateSingleton; })(); // 創建實例對象1 var a = new Singleton("a"); // 創建實例對象2 var b = new Singleton("b"); console.log(a===b);
這種單例模式我以前用過一次,但是使用起來很別扭,我也見過別人用這種方式實現過走馬燈的效果,因為走馬燈在我們的應用中絕大多數只有一個。
這里先說一下為什么感覺不對勁,因為在這個單例的構造函數中一共干了兩件事,一個是創建對象并打印實例名字,另一個是保證只有一個實例對象。這樣代碼量大的化不方便管理,應該盡量做到職責單一。
我們通常會將代碼改成下面這個樣子:
// 單例構造函數 function CreateSingleton (name) { this.name = name; this.getName(); }; // 獲取實例的名字 CreateSingleton.prototype.getName = function() { console.log(this.name) }; // 單例對象 var Singleton = (function(){ var instance; return function (name) { if(!instance) { instance = new CreateSingleton(name); } return instance; } })(); // 創建實例對象1 var a = new Singleton("a"); // 創建實例對象2 var b = new Singleton("b"); console.log(a===b);
這種實現方式我們就比較熟悉了,我們在開發中經常會使用中間類,通過它來實現原類所不具有的特殊功能。有的人把這種實現方式叫做代理,這的確是單例模式的一種應用,稍后將在代理模式進行詳解。
說了這么多我們還是在圍繞著傳統的單例模式實現在進行講解,那么具有JavaScript特色的單例模式是什么呢。
JavaScript單例模式在我們的開發中,很多同學可能并不知道單例到底是什么,應該如何使用單例,但是他們所寫的代碼卻剛好滿足了單例模式的要求。如要實現一個登陸彈窗,不管那個頁面或者在頁面的那個地方單擊登陸按鈕,都會彈出登錄窗。一些同學就會寫一個全局的對象來實現登陸窗口功能,是的,這樣的確可以實現所要求的登陸效果,也符合單例模式的要求,但是這種實現其實是一個巧合,或者一個美麗的錯誤。由于全局對象,或者說全局變量正好符合單例的能夠全局訪問,而且是唯一的。但是我們都知道,全局變量是可以被覆蓋的,特別是對于初級開發人員來說,剛開始不管定義什么基本都是全局的,這樣的好處是方便訪問,壞處是一不留意就會引起沖突,特別是在做一個團隊合作的大項目時,所以成熟的有經驗的開發人員盡量減少全局的聲明。
而在開發中我們避免全局變量污染的通常做法如下:
全局命名空間
使用閉包
它們的共同點是都可以定義自己的成員、存儲數據。區別是全局命名空間的所有方法和屬性都是公共的,而閉包可以實現方法和屬性的私有化。
惰性單例模式說實話,在我下決心學習設計模式之前我并不知道,單例模式還分惰性單例模式,直到我看了曾探大神的《JvaScript設計模式與開發實踐》后才知道了還有惰性單例模式,那么什么是惰性單例模式呢?在說惰性單例模式之前,請允許我先說一個我們都知道的lazyload加載圖片,它就是惰性加載,只當含有圖片資源的dom元素出現在媒體設備的可視區時,圖片資源才會被加載,這種加載模式就是惰性加載;還有就是下拉刷新資源也是惰性加載,當你觸發下拉刷新事件資源才會被加載等。而惰性單例模式的原理也是這樣的,只有當觸發創建實例對象時,實例對象才會被創建。這樣的實例對象創建方式在開發中很有必要的。
就如同我們剛開始介紹的用 Singleton.getInstance 創建實例對象一樣,雖然這種方式實現了惰性單例,但是正如我們剛開始說的那樣這并不是一個好的實現方式。下面就來介紹一個好的實現方式。
遮罩層相信大家對它都不陌生。它在開發中比較常見,實現起來也比較簡單。在每個人的開發中實現的方式不盡相同。這個最好的實現方式還是用單例模式。有的人實現直接在頁面中加入一個div然后設置display為none,這樣不管我們是否使用遮罩層頁面都會加載這個div,如果是多個頁面就是多個div的開銷;也有的人使用js創建一個div,當需要時就用將其加入到body中,如果不需要就刪除,這樣頻繁地操作dom對頁面的性能也是一種消耗;還有的人是在前一種的基礎上用一個標識符來判斷,當遮罩層是第一次出現就向頁面添加,不需要時隱藏,如果不是就是用前一次的添加的。
實現代碼如下:
// html // js var createMask = (function() { var mask; return function() { if(!mask) { // 創建div元素 var mask = document.createElement("div"); // 設置樣式 mask.style.position = "fixed"; mask.style.top = "0"; mask.style.right = "0"; mask.style.bottom = "0"; mask.style.left = "0"; mask.style.opacity = ""; mask.style.display = "none"; document.body.appendChild(mask); } return mask; } })(); document.getElementById("btn").onclick = function() { var maskLayer = createMask(); maskLayer.style.display = "block"; }
我們發現在開發中并不會多帶帶使用遮罩層,遮罩層和彈出窗是經常結合在一起使用,前面我們提到過登陸彈窗使用單例模式實現也是最適合的。那么我們是不是要將上面的代碼拷貝一份呢?當然我們還有好的實現方式,那就是將上面單例中代碼變化的部分和不變的部分,分離開來。
代碼如下:
var singleton = function(fn) { var instance; return function() { return instance || (instance = fn.apply(this, arguments)); } }; // 創建遮罩層 var createMask = function(){ // 創建div元素 var mask = document.createElement("div"); // 設置樣式 mask.style.position = "fixed"; mask.style.top = "0"; mask.style.right = "0"; mask.style.bottom = "0"; mask.style.left = "0"; mask.style.opacity = "o.75"; mask.style.backgroundColor = "#000"; mask.style.display = "none"; mask.style.zIndex = "98"; document.body.appendChild(mask); // 單擊隱藏遮罩層 mask.onclick = function(){ this.style.display = "none"; } return mask; }; // 創建登陸窗口 var createLogin = function() { // 創建div元素 var login = document.createElement("div"); // 設置樣式 login.style.position = "fixed"; login.style.top = "50%"; login.style.left = "50%"; login.style.zIndex = "100"; login.style.display = "none"; login.style.padding = "50px 80px"; login.style.backgroundColor = "#fff"; login.style.border = "1px solid #ccc"; login.style.borderRadius = "6px"; login.innerHTML = "login it"; document.body.appendChild(login); return login; }; document.getElementById("btn").onclick = function() { var oMask = singleton(createMask)(); oMask.style.display = "block"; var oLogin = singleton(createLogin)(); oLogin.style.display = "block"; var w = parseInt(oLogin.clientWidth); var h = parseInt(oLogin.clientHeight); }
在上面的實現中將單例模式的惰性實現部分提取出來,實現了惰性實現代碼的復用,其中使用apply改變改變了fn內的this指向,使用 || 預算簡化代碼的書寫。
設計模式相關文章
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92501.html
摘要:但是,這并不是采用單例的唯一原因。使用命名空間單例模式也被稱為模塊設計模式。函數內部聲明了一些局部函數和或變量。緊隨函數聲明放置即可立即執行外部函數,并將所得的對象文字費賠給變量。 JavaScript設計模式-第一部分:單例模式、組合模式和外觀模式 設計模式是一些可靠的編程方式,有助于保證代碼更加易于維護、擴展及分離,所有設計模式在創建大型JavaScript應用程序時均不可或缺 單...
摘要:此時我們創建的對象內保存靜態變量通過取值器訪問,最后將這個對象作為一個單例放在全局空間里面作為靜態變量單例對象供他人使用。 單例模式 又被稱為單體模式,是只允許實例化一次的對象類。有時我們也用一個對象來規劃一個命名空間,井井有條的管理對象上面的屬性和方法。 傳統的面向對象語言中單例模式的實現,均是單例對象從類中創建而來,在以類為中心的語言中,這是很常見的做法。如果需要某個對象,就必須先...
摘要:不符合設計模式中的單一職責的概念。引入代理實現單例模式引入代理實現單例模式的特點我們負責管理單例的邏輯移到了代理類中。的單例模式對比在以上的代碼中實現的單例模式都混入了傳統面向對象語言的特點。 聲明:這個系列為閱讀《JavaScript設計模式與開發實踐》 ----曾探@著一書的讀書筆記 1.單例模式的特點和定義 保證一個類僅有一個實例,并且提供一個訪問它的全局訪問點。 2.傳統面向對...
摘要:停更許久,近期計劃更新設計模式系列。單例模式是創建型設計模式的一種。雖然它不是正規的單例模式,但不可否認確實具備類單例模式的特點。適用場景單例模式的特點,意圖解決維護一個全局實例對象。 停更許久,近期計劃更新:設計模式系列。 showImg(https://segmentfault.com/img/bVbt7uw?w=800&h=600); 單例模式:限制類實例化次數只能一次,一個類只...
摘要:觀察構造函數的代碼,該構造函數實際上負責了兩件事情第一是創建對象和執行初始化方法,第二是保證只有一個對象。惰性單例在實際開發中非常有用,是單例模式的重點。 單例模式 單例模式的定義是: 保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。 單例模式是一種常用的模式,有一些對象我們往往只需要一個,比如線程池、全局緩存、瀏覽器的window對象等。例如,當我們點擊登錄按鈕時,頁面會彈出一...
摘要:在面向對象的語言中,比如,等,單例模式通常是定義類時將構造函數設為,保證對象不能在外部被出來,同時給類定義一個靜態的方法,用來獲取或者創建這個唯一的實例。 萬事開頭難,作為正經歷菜鳥賽季的前端player,已經忘記第一次告訴自己要寫一些東西出來是多久以的事情了。。。如果,你也和我一樣,那就像我一樣,從現在開始,從看到這篇文章開始,打開電腦,敲下你的第一篇文章(或者任何形式的文字)吧。 ...
閱讀 3538·2021-11-22 15:22
閱讀 3328·2019-08-30 15:54
閱讀 2724·2019-08-30 15:53
閱讀 783·2019-08-29 11:22
閱讀 3529·2019-08-29 11:14
閱讀 2073·2019-08-26 13:46
閱讀 2210·2019-08-26 13:24
閱讀 2277·2019-08-26 12:22