欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Javascript模塊化編程詳解

 更新時(shí)間:2014年12月01日 09:47:38   投稿:hebedich  
在這篇文章中,我將會(huì)回顧一下js模塊化編程的基礎(chǔ),并且將會(huì)講到一些真的非常值得一提的進(jìn)階話題,包括一個(gè)我認(rèn)為是我自創(chuàng)的模式。

模塊化編程是一種非常常見(jiàn)Javascript編程模式。它一般來(lái)說(shuō)可以使得代碼更易于理解,但是有許多優(yōu)秀的實(shí)踐還沒(méi)有廣為人知。

基礎(chǔ)

我們首先簡(jiǎn)單地概述一下,自從三年前Eric Miraglia(YUI的開(kāi)發(fā)者)第一次發(fā)表博客描述模塊化模式以來(lái)的一些模塊化模式。如果你已經(jīng)對(duì)于這些模塊化模式非常熟悉了,大可以直接跳過(guò)本節(jié),從“進(jìn)階模式”開(kāi)始閱讀。

匿名閉包

這是一種讓一切變?yōu)榭赡艿幕窘Y(jié)構(gòu),同時(shí)它也是Javascript最棒的特性。我們將簡(jiǎn)單地創(chuàng)建一個(gè)匿名函數(shù)并立即執(zhí)行它。所有的代碼將跑在這個(gè)函數(shù)內(nèi),生存在一個(gè)提供私有化的閉包中,它足以使得這些閉包中的變量能夠貫穿我們的應(yīng)用的整個(gè)生命周期。

復(fù)制代碼 代碼如下:

(function () {
    // ... all vars and functions are in this scope only
    // still maintains access to all globals
}());

注意這對(duì)包裹匿名函數(shù)的最外層括號(hào)。因?yàn)镴avascript的語(yǔ)言特性,這對(duì)括號(hào)是必須的。在js中由關(guān)鍵詞function開(kāi)頭的語(yǔ)句總是會(huì)被認(rèn)為是函數(shù)聲明式。把這段代碼包裹在括號(hào)中就可以讓解釋器知道這是個(gè)函數(shù)表達(dá)式。

全局變量導(dǎo)入

Javascript有一個(gè)特性叫做隱式全局變量。無(wú)論一個(gè)變量名在哪兒被用到了,解釋器會(huì)根據(jù)作用域鏈來(lái)反向找到這個(gè)變量的var聲明語(yǔ)句。如果沒(méi)有找到var聲明語(yǔ)句,那么這個(gè)變量就會(huì)被視為全局變量。如果這個(gè)變量用在一句賦值語(yǔ)句中,同時(shí)這個(gè)變量又不存在時(shí),就會(huì)創(chuàng)建出一個(gè)全局變量。這意味著在匿名閉包中使用或創(chuàng)建全局變量是很容易的。不幸的是,這會(huì)導(dǎo)致寫(xiě)出的代碼極難維護(hù),因?yàn)閷?duì)于人的直觀感受來(lái)說(shuō),一眼根本分不清那些是全局的變量。

幸運(yùn)的是,我們的匿名函數(shù)提供了簡(jiǎn)單的變通方法。只要將全局變量作為參數(shù)傳遞到我們的匿名函數(shù)中,就可以得到比隱式全局變量更清晰又快速的代碼了。下面是示例:

復(fù)制代碼 代碼如下:

(function ($, YAHOO) {
    // now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));

模塊導(dǎo)出

有時(shí)你不僅想要使用全局變量,你還想要聲明它們,以供反復(fù)使用。我們可以很容易地通過(guò)導(dǎo)出它們來(lái)做到這一點(diǎn)——通過(guò)匿名函數(shù)的返回值。這樣做將會(huì)完成一個(gè)基本的模塊化模式雛形,接下來(lái)會(huì)是一個(gè)完整的例子:

復(fù)制代碼 代碼如下:

var MODULE = (function () {
    var my = {},
        privateVariable = 1;
    function privateMethod() {
        // ...
    }
    my.moduleProperty = 1;
    my.moduleMethod = function () {
        // ...
    };
    return my;
}());

注意我們已經(jīng)聲明了一個(gè)叫做MODULE的全局模塊,它擁有2個(gè)公有的屬性:一個(gè)叫做MODULE.moduleMethod的方法和一個(gè)叫做MODULE.moduleProperty的變量。另外,它還維護(hù)了一個(gè)利用匿名函數(shù)閉包的、私有的內(nèi)置狀態(tài)。同時(shí),我們可以很容易地導(dǎo)入需要的全局變量,并像之前我們所學(xué)到的那樣來(lái)使用這個(gè)模塊化模式。

進(jìn)階模式

上面一節(jié)所描述的基礎(chǔ)已經(jīng)足以應(yīng)對(duì)許多情況,現(xiàn)在我們可以將這個(gè)模塊化模式進(jìn)一步的發(fā)展,創(chuàng)建更多強(qiáng)大的、可擴(kuò)展的結(jié)構(gòu)。讓我們從MODULE模塊開(kāi)始,一一介紹這些進(jìn)階模式。

放大模式

整個(gè)模塊必須在一個(gè)文件中是模塊化模式的一個(gè)限制。任何一個(gè)參與大型項(xiàng)目的人都會(huì)明白將js拆分多個(gè)文件的價(jià)值。幸運(yùn)的是,我們擁有一個(gè)很棒的實(shí)現(xiàn)來(lái)放大模塊。首先,我們導(dǎo)入一個(gè)模塊,并為它添加屬性,最后再導(dǎo)出它。下面是一個(gè)例子——從原本的MODULE中放大它:

復(fù)制代碼 代碼如下:

var MODULE = (function (my) {
    my.anotherMethod = function () {
        // added method...
    };
    return my;
}(MODULE));

我們用var關(guān)鍵詞來(lái)保證一致性,雖然它在此處不是必須的。在這段代碼執(zhí)行完之后,我們的模塊就已經(jīng)擁有了一個(gè)新的、叫做MODULE.anotherMethod的公有方法。這個(gè)放大文件也會(huì)維護(hù)它自己的私有內(nèi)置狀態(tài)和導(dǎo)入的對(duì)象。

寬放大模式

我們的上面例子需要我們的初始化模塊最先被執(zhí)行,然后放大模塊才能執(zhí)行,當(dāng)然有時(shí)這可能也不一定是必需的。Javascript應(yīng)用可以做到的、用來(lái)提升性能的、最棒的事之一就是異步執(zhí)行腳本。我們可以創(chuàng)建靈活的多部分模塊并通過(guò)寬放大模式使它們可以以任意順序加載。每一個(gè)文件都需要按下面的結(jié)構(gòu)組織:

復(fù)制代碼 代碼如下:

var MODULE = (function (my) {
    // add capabilities...
    return my;
}(MODULE || {}));

在這個(gè)模式中,var表達(dá)式使必需的。注意如果MODULE還未初始化過(guò),這句導(dǎo)入語(yǔ)句會(huì)創(chuàng)建MODULE。這意味著你可以用一個(gè)像LABjs的工具來(lái)并行加載你所有的模塊文件,而不會(huì)被阻塞。

緊放大模式

寬放大模式非常不錯(cuò),但它也會(huì)給你的模塊帶來(lái)一些限制。最重要的是,你不能安全地覆蓋模塊的屬性。你也無(wú)法在初始化的時(shí)候,使用其他文件中的屬性(但你可以在運(yùn)行的時(shí)候用)。緊放大模式包含了一個(gè)加載的順序序列,并且允許覆蓋屬性。這兒是一個(gè)簡(jiǎn)單的例子(放大我們的原始MODULE):

復(fù)制代碼 代碼如下:

var MODULE = (function (my) {
    var old_moduleMethod = my.moduleMethod;
    my.moduleMethod = function () {
        // method override, has access to old through old_moduleMethod...
    };
    return my;
}(MODULE));

我們?cè)谏厦娴睦又懈采w了MODULE.moduleMethod的實(shí)現(xiàn),但在需要的時(shí)候,可以維護(hù)一個(gè)對(duì)原來(lái)方法的引用。

克隆與繼承

復(fù)制代碼 代碼如下:

var MODULE_TWO = (function (old) {
    var my = {},
        key;
    for (key in old) {
        if (old.hasOwnProperty(key)) {
            my[key] = old[key];
        }
    }
    var super_moduleMethod = old.moduleMethod;
    my.moduleMethod = function () {
        // override method on the clone, access to super through super_moduleMethod
    };
    return my;
}(MODULE));

這個(gè)模式可能是最缺乏靈活性的一種選擇了。它確實(shí)使得代碼顯得很整潔,但那是用靈活性的代價(jià)換來(lái)的。正如我上面寫(xiě)的這段代碼,如果某個(gè)屬性是對(duì)象或者函數(shù),它將不會(huì)被復(fù)制,而是會(huì)成為這個(gè)對(duì)象或函數(shù)的第二個(gè)引用。修改了其中的某一個(gè)就會(huì)同時(shí)修改另一個(gè)(譯者注:因?yàn)樗鼈兏揪褪且粋€(gè)?。。?。這可以通過(guò)遞歸克隆過(guò)程來(lái)解決這個(gè)對(duì)象克隆問(wèn)題,但函數(shù)克隆可能無(wú)法解決,也許用eval可以解決吧。因此,我在這篇文章中講述這個(gè)方法僅僅是考慮到文章的完整性。

跨文件私有變量

把一個(gè)模塊分到多個(gè)文件中有一個(gè)重大的限制:每一個(gè)文件都維護(hù)了各自的私有變量,并且無(wú)法訪問(wèn)到其他文件的私有變量。但這個(gè)問(wèn)題是可以解決的。這里有一個(gè)維護(hù)跨文件私有變量的、寬放大模塊的例子:

復(fù)制代碼 代碼如下:

var MODULE = (function (my) {
    var _private = my._private = my._private || {},
        _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
        },
        _unseal = my._unseal = my._unseal || function () {
            my._private = _private;
            my._seal = _seal;
            my._unseal = _unseal;
        };
    // permanent access to _private, _seal, and _unseal
    return my;
}(MODULE || {}));

所有文件可以在它們各自的_private變量上設(shè)置屬性,并且它理解可以被其他文件訪問(wèn)。一旦這個(gè)模塊加載完成,應(yīng)用程序可以調(diào)用MODULE._seal()來(lái)防止外部對(duì)內(nèi)部_private的調(diào)用。如果這個(gè)模塊需要被重新放大,在任何一個(gè)文件中的內(nèi)部方法可以在加載新的文件前調(diào)用_unseal(),并在新文件執(zhí)行好以后再次調(diào)用_seal()。我如今在工作中使用這種模式,而且我在其他地方還沒(méi)有見(jiàn)過(guò)這種方法。我覺(jué)得這是一種非常有用的模式,很值得就這個(gè)模式本身寫(xiě)一篇文章。

子模塊

我們的最后一種進(jìn)階模式是顯而易見(jiàn)最簡(jiǎn)單的。創(chuàng)建子模塊有許多優(yōu)秀的實(shí)例。這就像是創(chuàng)建一般的模塊一樣:

復(fù)制代碼 代碼如下:

MODULE.sub = (function () {
    var my = {};
    // ...
    return my;
}());

雖然這看上去很簡(jiǎn)單,但我覺(jué)得還是值得在這里提一提。子模塊擁有一切一般模塊的進(jìn)階優(yōu)勢(shì),包括了放大模式和私有化狀態(tài)。

結(jié)論

大多數(shù)進(jìn)階模式可以結(jié)合到一起來(lái)創(chuàng)建一個(gè)更為有用的模式。如果實(shí)在要我推薦一種設(shè)計(jì)復(fù)雜應(yīng)用程序的模塊化模式的化,我會(huì)選擇結(jié)合寬放大模式、私有變量和子模塊。

我還未考慮過(guò)這些模式的性能問(wèn)題,但我寧愿把這轉(zhuǎn)化為一個(gè)更簡(jiǎn)單的思考方式:如果一個(gè)模塊化模式有很好的性能,那么它能夠把最小化做的很棒,使得下載這個(gè)腳本文件更快。使用寬放大模式可以允許簡(jiǎn)單的非阻塞并行下載,這就會(huì)加快下載速度。初始化時(shí)間可能會(huì)稍慢于其他方法,但權(quán)衡利弊后這還是值得的。只要全局變量導(dǎo)入準(zhǔn)確,運(yùn)行時(shí)性能應(yīng)該會(huì)不會(huì)受到影響,而且還有可能在子模塊中通過(guò)用私有變量縮短引用鏈來(lái)得到更快的運(yùn)行速度。

作為結(jié)束,這里是一個(gè)子模塊動(dòng)態(tài)地把自身加載到它的父模塊的例子(如果父模塊不存在則創(chuàng)建它)。為了簡(jiǎn)潔,我把私有變量給去除了,當(dāng)然加上私有變量也是很簡(jiǎn)單的啦。這種編程模式允許一整個(gè)復(fù)雜層級(jí)結(jié)構(gòu)代碼庫(kù)通過(guò)子模塊并行地完成加載。

復(fù)制代碼 代碼如下:

var UTIL = (function (parent, $) {
    var my = parent.ajax = parent.ajax || {};
    my.get = function (url, params, callback) {
        // ok, so I'm cheating a bit :)
        return $.getJSON(url, params, callback);
    };
    // etc...
    return parent;
}(UTIL || {}, jQuery));

本文總結(jié)了當(dāng)前"Javascript模塊化編程"的最佳實(shí)踐,說(shuō)明如何投入實(shí)用。雖然這不是初級(jí)教程,但是只要稍稍了解Javascript的基本語(yǔ)法,就能看懂。

相關(guān)文章

  • 深入理解javascript變量聲明

    深入理解javascript變量聲明

    本文是談?wù)勛约簩?duì)于javascript中變量聲明的一些看法、感想和理解,算是自己的一個(gè)小總結(jié)吧,分享出來(lái)給大家,希望對(duì)小伙伴們能有所幫助
    2014-11-11
  • 淺析js綁定事件的常用方法

    淺析js綁定事件的常用方法

    下面小編就為大家?guī)?lái)一篇淺析js綁定事件的常用方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-05-05
  • 詳解原生JS動(dòng)態(tài)添加和刪除類(lèi)

    詳解原生JS動(dòng)態(tài)添加和刪除類(lèi)

    這篇文章主要介紹了原生JS動(dòng)態(tài)添加和刪除類(lèi),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • js onkeypress與onkeydown 事件區(qū)別詳細(xì)說(shuō)明

    js onkeypress與onkeydown 事件區(qū)別詳細(xì)說(shuō)明

    本文將詳細(xì)介紹js onkeypress與onkeydown 事件區(qū)別:一個(gè)放開(kāi)一個(gè)沒(méi)有放開(kāi),onkeydown先于onkeypress 發(fā)生,需要的朋友可以參考下
    2012-12-12
  • 簡(jiǎn)介JavaScript中的getSeconds()方法的使用

    簡(jiǎn)介JavaScript中的getSeconds()方法的使用

    這篇文章主要介紹了簡(jiǎn)介JavaScript中的getSeconds()方法的使用,是JS入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-06-06
  • 深入學(xué)習(xí)JavaScript中的Rest參數(shù)和參數(shù)默認(rèn)值

    深入學(xué)習(xí)JavaScript中的Rest參數(shù)和參數(shù)默認(rèn)值

    這篇文章主要介紹了深入學(xué)習(xí)JavaScript中的Rest參數(shù)和參數(shù)默認(rèn)值,是JS入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-07-07
  • 關(guān)于JSON的定義以及如何使用

    關(guān)于JSON的定義以及如何使用

    這篇文章主要介紹了關(guān)于JSON的定義以及如何使用,JSON 的名稱中雖然帶有JavaScript,但這是指其語(yǔ)法規(guī)則是參考JavaScript對(duì)象的,而不是指只能用于JavaScript語(yǔ)言,需要的朋友可以參考下
    2023-07-07
  • prototype.js常用函數(shù)詳解

    prototype.js常用函數(shù)詳解

    本文主要介紹prototype.js中各個(gè)函數(shù)的用法,希望能幫到大家,有需要的朋友可以參考一下。
    2016-06-06
  • JavaScript中使用Math.floor()方法對(duì)數(shù)字取整

    JavaScript中使用Math.floor()方法對(duì)數(shù)字取整

    這篇文章主要介紹了JavaScript中使用Math.floor()方法對(duì)數(shù)字取整,是JS入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-06-06
  • JavaScript中的運(yùn)算符種類(lèi)及其規(guī)則介紹

    JavaScript中的運(yùn)算符種類(lèi)及其規(guī)則介紹

    JavaScript中的運(yùn)算符有很多,主要分為算術(shù)運(yùn)算符,等同全同運(yùn)算符,比較運(yùn)算符,字符串運(yùn)算符,邏輯運(yùn)算符,賦值運(yùn)算符等,它們都有一個(gè)自己的運(yùn)算規(guī)則,在本文為大家介紹下
    2013-09-09

最新評(píng)論