摘要:本系列為設(shè)計(jì)模式與開發(fā)實(shí)踐作者曾探學(xué)習(xí)總結(jié),如想深入了解,請(qǐng)支持作者原版單例模式實(shí)現(xiàn)單例模式單例模式的定義是保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
本系列為《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》(作者:曾探)學(xué)習(xí)總結(jié),如想深入了解,請(qǐng)支持作者原版
單例模式 實(shí)現(xiàn)單例模式單例模式的定義是:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
單例模式是一種常用的模式,有一些對(duì)象我們往往只需要一個(gè),比如登錄窗口,這個(gè)窗口是唯一的,無論我們點(diǎn)擊多少次登錄按鈕,這個(gè)窗口只會(huì)被創(chuàng)建一次,那么這個(gè)窗口就適合用單例模式來創(chuàng)建。
要實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn)的單例模式并不復(fù)雜,無非是用一個(gè)變量來標(biāo)志當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建過對(duì)象,如果是,則在下一次獲取該類的實(shí)例時(shí),直接返回之前創(chuàng)建的對(duì)象。代碼如下:
var Singleton=function(name){ this.name=name; this.instance=null; }; Singleton.prototype.getName=function(){ alert(this.name); }; Singleton.getInstance=function(){ if(!this.instance){ this.instance=new Singleton(name); } return this.instance; }; var a=Singleton.getInstance("sven1"); var b=Singleton.getInstance("sven2"); alert(a===b);//true
或者
var Singleton=function(name){ this.name=name; }; Singleton.prototype.getName=function(){ alert(this.name); }; Singleton.getInstance=(function(){ var instance=null; return function(name){ if(!instance){ instance=new Singleton(name); } return instance; } })();
我們通過Singleton.getInstance來獲取Singleton類的唯一對(duì)象,這種方式相對(duì)簡(jiǎn)單,但是不透明。跟以往通過new XXX的方式獲取對(duì)象不同,這里偏要使用Singleton.getInstance來獲取對(duì)象,所以這段代碼的意義并不大。
透明的單例模式我們現(xiàn)在的目標(biāo)是實(shí)現(xiàn)一個(gè)透明的單例類。
var CreateDiv = (function() { var instance; var CreateDiv = function(html) { if (instance) { return instance; } this.html = html; this.init(); return instance = this; }; CreateDiv.prototype.init = function() { var div = document.createElement("div"); div.innerHtml = this.html; document.body.appendChild(div); }; return CreateDiv; })() var a = new CreateDiv("sven1"); var b = new CreateDiv("sven2"); alert(a===b);//true
雖然現(xiàn)在完成了一個(gè)透明的單例類的編寫,但它同樣有一些缺點(diǎn)。為了把instance封裝起來,我們使用了自執(zhí)行的匿名函數(shù)和閉包,并且讓這個(gè)匿名函數(shù)返回真正的Singleton構(gòu)造方法,這增加了一些程序的復(fù)雜度,閱讀起來也不是很舒服。
假設(shè)我們某天需要讓這個(gè)單例類變成一個(gè)普通的類,即可以產(chǎn)生多個(gè)實(shí)例,那我們必須改寫CreateDiv構(gòu)造函數(shù),這種修改會(huì)帶來很多不必要的麻煩。
我們首先創(chuàng)建一個(gè)普通的CreateDiv類:
var CreateDiv = function(html) { this.html = html; this.init(); }; CreateDiv.prototype.init = function() { var div = document.createElement("div"); div.innerHtml = this.html; document.body.appendChild(div); };
接下來引入代理類ProxySingletonCreate:
var ProxySingletonCreate = (function() { var instance; return function(html) { if (!instance) { instance = new CreateDiv(html); } return instance; } })(); var a = new ProxySingletonCreate("sven1"); var b = new ProxySingletonCreate("sven2"); console.log(a === b);
這樣一來,CreateDiv和ProxySingletonCreate組合起來,實(shí)現(xiàn)了單例模式的效果。
JavaScript中的單例模式前面提到的幾種單例模式的實(shí)現(xiàn),更多的是接近傳統(tǒng)面向?qū)ο笳Z言中的實(shí)現(xiàn),單例對(duì)象從類中創(chuàng)建而來。但JavaScript其實(shí)是一門無類的語言,所以生搬單例模式的概念并無意義。
單例模式的核心是:確保只有一個(gè)實(shí)例,并提供全局訪問。
全局變量不是單例模式,但在實(shí)際應(yīng)用中,我們經(jīng)常會(huì)把全局變量當(dāng)成單例來使用。
例如:
var a = {};
全局變量可以滿足上述的兩個(gè)條件,但卻存在許多問題:它很容易造成命名空間污染。作為普通的開發(fā)者,我們有必要減少全局變量的使用,一下幾種方式可以相對(duì)降低全局變量帶來的命名污染。
使用命名空間最簡(jiǎn)單的方法依然是使用對(duì)象字面量方式:
var namespace1={ a:function(){ }, b:function(){ } };
我們還可以動(dòng)態(tài)的創(chuàng)建命名空間:
var myApp = {}; myApp.namespace = function(name) { var parts = name.split("."); var current = myApp; for (var i in parts) { if (!current[parts[i]]) { current[parts[i]] = {}; } current = current[parts[i]]; } }; myApp.namespace("event"); myApp.namespace("dom.style"); console.log(myApp);使用閉包封裝私有變量
var user=(function(){ var _name="sven",_age=29; return { getUserInfo:function(){ return _name+"_"+_age; } } })();惰性單例
惰性單例指的是在需要的時(shí)候才創(chuàng)建對(duì)象實(shí)例。惰性單例是單例模式的重點(diǎn),這種技術(shù)在實(shí)際開發(fā)中非常有用。
我們先抽取出一個(gè)管理單例的邏輯對(duì)象:
var getSingle=function(fn){ var result; return function(){ return result||(result=fn.apply(this.arguments)); } };
創(chuàng)建對(duì)象的方法fn被當(dāng)做參數(shù)傳入getSingle。
var getSingle = function(fn) { var result; return function() { return result || (result = fn.apply(this.arguments)); }; }; var createLoginLayer = function() { var div = document.createElement("div"); div.innerHTML = "我是登錄窗"; div.style.width = "100px"; div.style.height = "100px"; div.style.background = "red"; document.body.appendChild(div); return div; }; aa = getSingle(createLoginLayer); aa();
result變量因?yàn)樯碓?b>閉包中,永遠(yuǎn)不會(huì)被銷毀。在將來的請(qǐng)求中,如果result已經(jīng)被賦值,那么他將返回這個(gè)值。
以下是演示地址:
惰性單例演示地址
其他演示地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78844.html
摘要:所以程序在引入文件的時(shí)候用了單例模式,一個(gè)文件實(shí)例化一次,這種做法無疑是好的,但是也容易引起。在我們平時(shí)的開發(fā)過程中,可以借鑒這兩種方式去緩存變量,節(jié)點(diǎn)等。 這一章作者講了一個(gè)例子,就是在用單例模式生成一個(gè)dom節(jié)點(diǎn),還要做到只有訪問的時(shí)候才創(chuàng)建,后續(xù)訪問直接用前面創(chuàng)建的。那么實(shí)際開發(fā)中我們會(huì)用到這個(gè)模式嗎?現(xiàn)在我們基本都是用vue,react,angular開發(fā),不太會(huì)直接去操作do...
摘要:最佳實(shí)踐使用代理方式實(shí)現(xiàn)單例模式,使用一個(gè)代理函數(shù)來實(shí)現(xiàn)實(shí)單例例化原生的代碼摘自設(shè)計(jì)模式與開發(fā)實(shí)踐下來代理類測(cè)試函數(shù)返回版的用實(shí)現(xiàn)的單例模式代碼已創(chuàng)建張三李四返回 說明:只要實(shí)例化一次,超過一次的實(shí)例化過程會(huì)返回之前實(shí)例化的結(jié)果,而不會(huì)在內(nèi)存中再次寫入新的實(shí)例對(duì)象。----類似于once。 需要遵守的原則:?jiǎn)我宦氊?zé)的原則,每一個(gè)類或者函數(shù)只負(fù)責(zé)一個(gè)功能。 最佳實(shí)踐:使用代理方式實(shí)現(xiàn)單例...
摘要:大潮來襲前端開發(fā)能做些什么去年谷歌和火狐針對(duì)提出了的標(biāo)準(zhǔn),顧名思義,即的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的標(biāo)準(zhǔn)讓我們可以使用語言來開發(fā)。 VR 大潮來襲 --- 前端開發(fā)能做些什么 去年谷歌和火狐針對(duì) WebVR 提出了 WebVR API 的標(biāo)準(zhǔn),顧名思義,WebVR 即 web + VR 的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的 API 標(biāo)準(zhǔn)讓我們可以使用 ...
閱讀 3672·2021-11-15 11:37
閱讀 2322·2021-09-24 10:39
閱讀 2460·2021-07-25 21:37
閱讀 1446·2019-08-30 15:56
閱讀 2588·2019-08-30 15:55
閱讀 957·2019-08-30 15:54
閱讀 2129·2019-08-30 14:21
閱讀 858·2019-08-30 11:24