成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript 單例模式

lijinke666 / 2306人閱讀

摘要:實(shí)現(xiàn)代碼如下創(chuàng)建元素設(shè)置樣式我們發(fā)現(xiàn)在開發(fā)中并不會(huì)多帶帶使用遮罩層,遮罩層和彈出窗是經(jīng)常結(jié)合在一起使用,前面我們提到過(guò)登陸彈窗使用單例模式實(shí)現(xiàn)也是最適合的。

定義

確保一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。

單例模式使用的場(chǎng)景

比如線程池、全局緩存等。我們所熟知的瀏覽器的window對(duì)象就是一個(gè)單例,在JavaScript開發(fā)中,對(duì)于這種只需要一個(gè)的對(duì)象,我們的實(shí)現(xiàn)往往使用單例。

實(shí)現(xiàn)單例模式 (不透明的)

一般我們是這樣實(shí)現(xiàn)單例的,用一個(gè)變量來(lái)標(biāo)志當(dāng)前的類已經(jīng)創(chuàng)建過(guò)對(duì)象,如果下次獲取當(dāng)前類的實(shí)例時(shí),直接返回之前創(chuàng)建的對(duì)象即可。代碼如下:

// 定義一個(gè)類
function Singleton(name) {
    this.name = name;
    this.instance = null;
}
// 原型擴(kuò)展類的一個(gè)方法getName()
Singleton.prototype.getName = function() {
    console.log(this.name)
};
// 獲取類的實(shí)例
Singleton.getInstance = function(name) {
    if(!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance
};

// 獲取對(duì)象1
var a = Singleton.getInstance("a");
// 獲取對(duì)象2
var b = Singleton.getInstance("b");
// 進(jìn)行比較
console.log(a === b);

我們也可以使用閉包來(lái)實(shí)現(xiàn):

function Singleton(name) {
    this.name = name;
}
// 原型擴(kuò)展類的一個(gè)方法getName()
Singleton.prototype.getName = function() {
    console.log(this.name)
};
// 獲取類的實(shí)例
Singleton.getInstance = (function() {
    var instance = null;
    return function(name) {
        if(!this.instance) {
            this.instance = new Singleton(name);
        }
        return this.instance
    }        
})();

// 獲取對(duì)象1
var a = Singleton.getInstance("a");
// 獲取對(duì)象2
var b = Singleton.getInstance("b");
// 進(jìn)行比較
console.log(a === b);

這個(gè)單例實(shí)現(xiàn)獲取對(duì)象的方式經(jīng)常見于新手的寫法,這種方式獲取對(duì)象雖然簡(jiǎn)單,但是這種實(shí)現(xiàn)方式不透明。知道的人可以通過(guò) Singleton.getInstance() 獲取對(duì)象,不知道的需要研究代碼的實(shí)現(xiàn),這樣不好。這與我們常見的用 new 關(guān)鍵字來(lái)獲取對(duì)象有出入,實(shí)際意義不大。

實(shí)現(xiàn)單例模式 (透明的)
var Singleton = (function(){
    var instance;
    var CreateSingleton = function (name) {
        this.name = name;

        if(instance) {
            return instance;
        }
        // 打印實(shí)例名字
        this.getName();

        // instance = this;
        // return instance;
        return instance = this;
    }
    // 獲取實(shí)例的名字
    CreateSingleton.prototype.getName = function() {
        console.log(this.name)
    }

    return CreateSingleton;
})();
// 創(chuàng)建實(shí)例對(duì)象1
var a = new Singleton("a");
// 創(chuàng)建實(shí)例對(duì)象2
var b = new Singleton("b");

console.log(a===b);

這種單例模式我以前用過(guò)一次,但是使用起來(lái)很別扭,我也見過(guò)別人用這種方式實(shí)現(xiàn)過(guò)走馬燈的效果,因?yàn)樽唏R燈在我們的應(yīng)用中絕大多數(shù)只有一個(gè)。

這里先說(shuō)一下為什么感覺(jué)不對(duì)勁,因?yàn)樵谶@個(gè)單例的構(gòu)造函數(shù)中一共干了兩件事,一個(gè)是創(chuàng)建對(duì)象并打印實(shí)例名字,另一個(gè)是保證只有一個(gè)實(shí)例對(duì)象。這樣代碼量大的化不方便管理,應(yīng)該盡量做到職責(zé)單一。

我們通常會(huì)將代碼改成下面這個(gè)樣子:

// 單例構(gòu)造函數(shù)
function CreateSingleton (name) {
    this.name = name;
    this.getName();
};

// 獲取實(shí)例的名字
CreateSingleton.prototype.getName = function() {
    console.log(this.name)
};
// 單例對(duì)象
var Singleton = (function(){
    var instance;
    return function (name) {
        if(!instance) {
            instance = new CreateSingleton(name);
        }
        return instance;
    }
})();

// 創(chuàng)建實(shí)例對(duì)象1
var a = new Singleton("a");
// 創(chuàng)建實(shí)例對(duì)象2
var b = new Singleton("b");

console.log(a===b);

這種實(shí)現(xiàn)方式我們就比較熟悉了,我們?cè)陂_發(fā)中經(jīng)常會(huì)使用中間類,通過(guò)它來(lái)實(shí)現(xiàn)原類所不具有的特殊功能。有的人把這種實(shí)現(xiàn)方式叫做代理,這的確是單例模式的一種應(yīng)用,稍后將在代理模式進(jìn)行詳解。

說(shuō)了這么多我們還是在圍繞著傳統(tǒng)的單例模式實(shí)現(xiàn)在進(jìn)行講解,那么具有JavaScript特色的單例模式是什么呢。

JavaScript單例模式

在我們的開發(fā)中,很多同學(xué)可能并不知道單例到底是什么,應(yīng)該如何使用單例,但是他們所寫的代碼卻剛好滿足了單例模式的要求。如要實(shí)現(xiàn)一個(gè)登陸彈窗,不管那個(gè)頁(yè)面或者在頁(yè)面的那個(gè)地方單擊登陸按鈕,都會(huì)彈出登錄窗。一些同學(xué)就會(huì)寫一個(gè)全局的對(duì)象來(lái)實(shí)現(xiàn)登陸窗口功能,是的,這樣的確可以實(shí)現(xiàn)所要求的登陸效果,也符合單例模式的要求,但是這種實(shí)現(xiàn)其實(shí)是一個(gè)巧合,或者一個(gè)美麗的錯(cuò)誤。由于全局對(duì)象,或者說(shuō)全局變量正好符合單例的能夠全局訪問(wèn),而且是唯一的。但是我們都知道,全局變量是可以被覆蓋的,特別是對(duì)于初級(jí)開發(fā)人員來(lái)說(shuō),剛開始不管定義什么基本都是全局的,這樣的好處是方便訪問(wèn),壞處是一不留意就會(huì)引起沖突,特別是在做一個(gè)團(tuán)隊(duì)合作的大項(xiàng)目時(shí),所以成熟的有經(jīng)驗(yàn)的開發(fā)人員盡量減少全局的聲明。

而在開發(fā)中我們避免全局變量污染的通常做法如下:

全局命名空間

使用閉包

它們的共同點(diǎn)是都可以定義自己的成員、存儲(chǔ)數(shù)據(jù)。區(qū)別是全局命名空間的所有方法和屬性都是公共的,而閉包可以實(shí)現(xiàn)方法和屬性的私有化。

惰性單例模式

說(shuō)實(shí)話,在我下決心學(xué)習(xí)設(shè)計(jì)模式之前我并不知道,單例模式還分惰性單例模式,直到我看了曾探大神的《JvaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》后才知道了還有惰性單例模式,那么什么是惰性單例模式呢?在說(shuō)惰性單例模式之前,請(qǐng)?jiān)试S我先說(shuō)一個(gè)我們都知道的lazyload加載圖片,它就是惰性加載,只當(dāng)含有圖片資源的dom元素出現(xiàn)在媒體設(shè)備的可視區(qū)時(shí),圖片資源才會(huì)被加載,這種加載模式就是惰性加載;還有就是下拉刷新資源也是惰性加載,當(dāng)你觸發(fā)下拉刷新事件資源才會(huì)被加載等。而惰性單例模式的原理也是這樣的,只有當(dāng)觸發(fā)創(chuàng)建實(shí)例對(duì)象時(shí),實(shí)例對(duì)象才會(huì)被創(chuàng)建。這樣的實(shí)例對(duì)象創(chuàng)建方式在開發(fā)中很有必要的。

就如同我們剛開始介紹的用 Singleton.getInstance 創(chuàng)建實(shí)例對(duì)象一樣,雖然這種方式實(shí)現(xiàn)了惰性單例,但是正如我們剛開始說(shuō)的那樣這并不是一個(gè)好的實(shí)現(xiàn)方式。下面就來(lái)介紹一個(gè)好的實(shí)現(xiàn)方式。

遮罩層相信大家對(duì)它都不陌生。它在開發(fā)中比較常見,實(shí)現(xiàn)起來(lái)也比較簡(jiǎn)單。在每個(gè)人的開發(fā)中實(shí)現(xiàn)的方式不盡相同。這個(gè)最好的實(shí)現(xiàn)方式還是用單例模式。有的人實(shí)現(xiàn)直接在頁(yè)面中加入一個(gè)div然后設(shè)置display為none,這樣不管我們是否使用遮罩層頁(yè)面都會(huì)加載這個(gè)div,如果是多個(gè)頁(yè)面就是多個(gè)div的開銷;也有的人使用js創(chuàng)建一個(gè)div,當(dāng)需要時(shí)就用將其加入到body中,如果不需要就刪除,這樣頻繁地操作dom對(duì)頁(yè)面的性能也是一種消耗;還有的人是在前一種的基礎(chǔ)上用一個(gè)標(biāo)識(shí)符來(lái)判斷,當(dāng)遮罩層是第一次出現(xiàn)就向頁(yè)面添加,不需要時(shí)隱藏,如果不是就是用前一次的添加的。

實(shí)現(xiàn)代碼如下:

// html



// js
var createMask = (function() {
    var mask;
    return function() {
        if(!mask) {
            // 創(chuàng)建div元素
            var mask = document.createElement("div");
            // 設(shè)置樣式
            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";
}

我們發(fā)現(xiàn)在開發(fā)中并不會(huì)多帶帶使用遮罩層,遮罩層和彈出窗是經(jīng)常結(jié)合在一起使用,前面我們提到過(guò)登陸彈窗使用單例模式實(shí)現(xiàn)也是最適合的。那么我們是不是要將上面的代碼拷貝一份呢?當(dāng)然我們還有好的實(shí)現(xiàn)方式,那就是將上面單例中代碼變化的部分和不變的部分,分離開來(lái)。

代碼如下:

var singleton = function(fn) {
    var instance;
    return function() {
        return instance || (instance = fn.apply(this, arguments));
    }
};
// 創(chuàng)建遮罩層
var createMask = function(){
    // 創(chuàng)建div元素
    var mask = document.createElement("div");
    // 設(shè)置樣式
    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;
};

// 創(chuàng)建登陸窗口
var createLogin = function() {
    // 創(chuàng)建div元素
    var login = document.createElement("div");
    // 設(shè)置樣式
    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);
}

在上面的實(shí)現(xiàn)中將單例模式的惰性實(shí)現(xiàn)部分提取出來(lái),實(shí)現(xiàn)了惰性實(shí)現(xiàn)代碼的復(fù)用,其中使用apply改變改變了fn內(nèi)的this指向,使用 || 預(yù)算簡(jiǎn)化代碼的書寫。

設(shè)計(jì)模式相關(guān)文章

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92501.html

相關(guān)文章

  • JavaScript設(shè)計(jì)模式-第一部分:單例模式、組合模式和外觀模式

    摘要:但是,這并不是采用單例的唯一原因。使用命名空間單例模式也被稱為模塊設(shè)計(jì)模式。函數(shù)內(nèi)部聲明了一些局部函數(shù)和或變量。緊隨函數(shù)聲明放置即可立即執(zhí)行外部函數(shù),并將所得的對(duì)象文字費(fèi)賠給變量。 JavaScript設(shè)計(jì)模式-第一部分:?jiǎn)卫J?、組合模式和外觀模式 設(shè)計(jì)模式是一些可靠的編程方式,有助于保證代碼更加易于維護(hù)、擴(kuò)展及分離,所有設(shè)計(jì)模式在創(chuàng)建大型JavaScript應(yīng)用程序時(shí)均不可或缺 單...

    betacat 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式單例模式

    摘要:此時(shí)我們創(chuàng)建的對(duì)象內(nèi)保存靜態(tài)變量通過(guò)取值器訪問(wèn),最后將這個(gè)對(duì)象作為一個(gè)單例放在全局空間里面作為靜態(tài)變量單例對(duì)象供他人使用。 單例模式 又被稱為單體模式,是只允許實(shí)例化一次的對(duì)象類。有時(shí)我們也用一個(gè)對(duì)象來(lái)規(guī)劃一個(gè)命名空間,井井有條的管理對(duì)象上面的屬性和方法。 傳統(tǒng)的面向?qū)ο笳Z(yǔ)言中單例模式的實(shí)現(xiàn),均是單例對(duì)象從類中創(chuàng)建而來(lái),在以類為中心的語(yǔ)言中,這是很常見的做法。如果需要某個(gè)對(duì)象,就必須先...

    zhaot 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式----單例模式

    摘要:不符合設(shè)計(jì)模式中的單一職責(zé)的概念。引入代理實(shí)現(xiàn)單例模式引入代理實(shí)現(xiàn)單例模式的特點(diǎn)我們負(fù)責(zé)管理單例的邏輯移到了代理類中。的單例模式對(duì)比在以上的代碼中實(shí)現(xiàn)的單例模式都混入了傳統(tǒng)面向?qū)ο笳Z(yǔ)言的特點(diǎn)。 聲明:這個(gè)系列為閱讀《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 ----曾探@著一書的讀書筆記 1.單例模式的特點(diǎn)和定義 保證一個(gè)類僅有一個(gè)實(shí)例,并且提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。 2.傳統(tǒng)面向?qū)?..

    selfimpr 評(píng)論0 收藏0
  • JavaScript 設(shè)計(jì)模式(一):單例模式

    摘要:停更許久,近期計(jì)劃更新設(shè)計(jì)模式系列。單例模式是創(chuàng)建型設(shè)計(jì)模式的一種。雖然它不是正規(guī)的單例模式,但不可否認(rèn)確實(shí)具備類單例模式的特點(diǎn)。適用場(chǎng)景單例模式的特點(diǎn),意圖解決維護(hù)一個(gè)全局實(shí)例對(duì)象。 停更許久,近期計(jì)劃更新:設(shè)計(jì)模式系列。 showImg(https://segmentfault.com/img/bVbt7uw?w=800&h=600); 單例模式:限制類實(shí)例化次數(shù)只能一次,一個(gè)類只...

    xialong 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐 | 04 - 單例模式

    摘要:觀察構(gòu)造函數(shù)的代碼,該構(gòu)造函數(shù)實(shí)際上負(fù)責(zé)了兩件事情第一是創(chuàng)建對(duì)象和執(zhí)行初始化方法,第二是保證只有一個(gè)對(duì)象。惰性單例在實(shí)際開發(fā)中非常有用,是單例模式的重點(diǎn)。 單例模式 單例模式的定義是: 保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。 單例模式是一種常用的模式,有一些對(duì)象我們往往只需要一個(gè),比如線程池、全局緩存、瀏覽器的window對(duì)象等。例如,當(dāng)我們點(diǎn)擊登錄按鈕時(shí),頁(yè)面會(huì)彈出一...

    awkj 評(píng)論0 收藏0
  • 再遇設(shè)計(jì)模式JavaScript

    摘要:在面向?qū)ο蟮恼Z(yǔ)言中,比如,等,單例模式通常是定義類時(shí)將構(gòu)造函數(shù)設(shè)為,保證對(duì)象不能在外部被出來(lái),同時(shí)給類定義一個(gè)靜態(tài)的方法,用來(lái)獲取或者創(chuàng)建這個(gè)唯一的實(shí)例。 萬(wàn)事開頭難,作為正經(jīng)歷菜鳥賽季的前端player,已經(jīng)忘記第一次告訴自己要寫一些東西出來(lái)是多久以的事情了。。。如果,你也和我一樣,那就像我一樣,從現(xiàn)在開始,從看到這篇文章開始,打開電腦,敲下你的第一篇文章(或者任何形式的文字)吧。 ...

    Clect 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<