JavaScript模塊化發(fā)展史

前兩天有朋友拿了這樣一段代碼來(lái)問(wèn)我严嗜,“我想把一段代碼寫(xiě)成模塊化的樣子晋涣,你幫我看看是不是這樣的笨鸡“邕叮”缤弦,代碼大概是這樣的:

(function(global) {
    var myModules = {
        name: 'xxx',
        location: 'chengdu',
        intro: function() {
                return `his name is ${myModules.name} and come from ${myModules.location}`
            },
        }
        // some other code...
        if(typeof module === 'undefined')
            global.myModules = myModules
        else
            module.exports = myModules
})(this)

“可是我這段代碼在全局還是能myModules這個(gè)屬性啊彻磁?”
我一臉懵碍沐,還有這種操作,為什么你的立即執(zhí)行函數(shù)要把this傳進(jìn)去呢衷蜓,這樣不久將里面的內(nèi)容掛在到了window上了嗎累提,他似懂非懂,我只好說(shuō)磁浇,你可能需要回頭去看看AMDCMD規(guī)范了刻恭,我大概能夠理解這其中的緣由,畢竟這段時(shí)間前端發(fā)展的速度飛快扯夭,加上webpack也不需要自己配鳍贾,包括vuereact交洗,angular在內(nèi)的框架類(lèi)庫(kù)都有一鍵生成項(xiàng)目的工具骑科,從而只需要使用下import * from '*'export default {},而這種便利會(huì)讓新人不再需要去學(xué)習(xí)基本原理就能快速上手构拳,畢竟現(xiàn)在都ES2018了呀咆爽。

  • 對(duì)象形式

最開(kāi)始的時(shí)候,為了減少全局變量置森,一般會(huì)使用一個(gè)對(duì)象的方式來(lái)對(duì)所有的變量方法進(jìn)行一個(gè)包裝:

    var obj = {
        a: 1,
        b: 2,
        sum: function(val) {
           return obj.a + obj.b + val
        },
        rest: function(val) {
           return val - obj.a - obj.b
        }
   }

以上代碼似乎解決了全局變量的問(wèn)題斗埂,但是其中的ab兩個(gè)變量還是可能被修改,其中包含的進(jìn)化有限凫海。

  • 立即執(zhí)行函數(shù)

回過(guò)頭來(lái)看文章開(kāi)頭的代碼呛凶,姑且不論以上代碼的錯(cuò)誤之處,稍作修改行贪,這算是最初的一種關(guān)于JavaScript模塊化的開(kāi)端漾稀,立即執(zhí)行函數(shù):

var add = (function(){
    var a = 1
    var b = 2
    function sum(count){
        return a + b + count
    }
    function rest(count){
        return count - a - b
    }
    return {
        rest: rest,
        sum: sum
    }
})()

這就是一種最簡(jiǎn)單的模塊化的方式,利用閉包的特性建瘫,設(shè)置了兩個(gè)只有在被暴露出來(lái)的addreduce方法內(nèi)部才能訪問(wèn)到的兩個(gè)變量崭捍,從而保證了函數(shù)的局部變量不可被修改的特性,這次的進(jìn)化用到了閉包啰脚,從而實(shí)現(xiàn)了部分有效的目的殷蛇。

  • 放大模式

其實(shí)開(kāi)頭的代碼更符合另外一種叫做放大模式的方法,不過(guò)一般來(lái)說(shuō)不會(huì)講window作為放大模式中被傳入的對(duì)象

    var globalObject = {
      fn1: function() {
        // todo...
      },
      // ...
    }
    globalObject = (function(obj) {
      var name = 'xxx'
      var location = 'xxx'
      function sum(val) { /* todo... */ }
      function rest(val) { /* todo... */ }
      obj.sum = sum
      obj.rest = rest
      return obj
    })(globalObject)

以這種形式來(lái)寫(xiě),可以讓全局變量盡量的減少粒梦,同時(shí)讓一個(gè)立即執(zhí)行函數(shù)中的代碼盡量做到精簡(jiǎn)收擦。

  • 但是這種放大模式也存在著問(wèn)題,比如當(dāng)globalObject內(nèi)容足夠多的時(shí)候谍倦,很可能會(huì)造成命名重復(fù)的情況,并且以上所有的方式都不可以減少script標(biāo)簽的數(shù)量泪勒,所以昼蛀,我們還是會(huì)被模塊的加載順序,命名空間沖突等問(wèn)題所困擾圆存,這時(shí)候叼旋,我們應(yīng)該跨入新時(shí)代了。

  • CMD規(guī)范

CMD規(guī)范來(lái)自阿里的框架seajs沦辙,當(dāng)初確實(shí)有挺多人使用夫植,不過(guò)現(xiàn)階段已經(jīng)不再維護(hù)了,我也不會(huì)油讯,就暫時(shí)不說(shuō)了详民,只列出來(lái)。

  • commonjs

同時(shí)陌兑,從2009年開(kāi)始沈跨,JavaScript就不再只是一種瀏覽器端的腳本語(yǔ)言了,nodejs的出現(xiàn)讓使用js開(kāi)發(fā)服務(wù)端變成了可能兔综,隨著node出現(xiàn)的東西還有一個(gè)叫做commonjs的規(guī)范饿凛,在這個(gè)規(guī)范中,每個(gè)文件都是一個(gè)模塊软驰,有著自己的作用域涧窒。

譬如,如下代碼

    // 文件a.js
    var a = 1
    // 文件b.js
    console.log(a) // a is not defined.

在這樣的特性下锭亏,a.jsb.js都有著自己獨(dú)有的作用域纠吴,要在b中對(duì)a進(jìn)行訪問(wèn)忧饭,就需要一種加載機(jī)制导盅,一般來(lái)說(shuō)禽绪,有兩種方法能夠做到:

方法1

    // 文件a.js
    global.a = 1
    // 文件b.js
    console.log(a) // 1

這種方法掛載在global上伸眶,當(dāng)然是不可取的纱皆。

方法2

    // 文件a.js
    exports.a = 1
    // 文件b.js
    var moduleA = require('./a')
    console.log(moduleA.a)
  • AMD規(guī)范

requirejs的出現(xiàn)讓script標(biāo)簽的減少變成了可能猴贰,在requirejs的時(shí)代揭绑,我們一般會(huì)使用jQuery坦报,underscore這類(lèi)的類(lèi)庫(kù)上煤,如果按照往常的樣子我們會(huì)將代碼寫(xiě)成下面這副模樣:

<script src="/js/lib/jquery.min.js"></script>
<script src="/js/lib/underscore.min.js"></script>
<script src="/js/app/index.js"></script>
<script src="/js/app/app.js"></script>
<!-- and so on... -->

這樣的代碼乍一看似乎沒(méi)什么問(wèn)題休玩,但是當(dāng)一個(gè)項(xiàng)目的代碼量上了一個(gè)量級(jí),一切就變得不是這么回事兒了,你會(huì)被困在加載順序拴疤,加載時(shí)間的問(wèn)題上永部,這也就是requirejs能夠出現(xiàn)的原因了。

requirejs中呐矾,你可以如此改寫(xiě)以上代碼:

    // `index.js`
   require(['js/lib/jquery.min', 'js/lib/underscore.min', 'js/app/app'], function($, _, app) {  /*  todo...  */  })
    // `app.js`
   define(['js/lib/jquery.min', 'js/lib/underscore.min'], function($, _) {  /*  todo...  */  })
<script data-main="/index.js" src="/js/require.js"></script>

這里當(dāng)然顯得更加優(yōu)雅了苔埋,在requirejs的推廣過(guò)程中,AMD規(guī)范也就應(yīng)運(yùn)而生了蜒犯,那么组橄,requirejs或者說(shuō)AMD規(guī)范到底解決了什么樣的問(wèn)題呢,主要有幾點(diǎn):

  1. AMD是“異步模塊定義”的縮寫(xiě)罚随,也就是說(shuō)玉工,其中內(nèi)容是異步加載的,從而讓頁(yè)面不被js的加載阻塞淘菩,最大程度上的避免了頁(yè)面假死等情況的產(chǎn)生遵班。
  2. AMD的一個(gè)好處在與依賴前置,所有被使用到的模塊都會(huì)被提前加載好潮改,從而加快運(yùn)行速度狭郑。

那么,commonjs規(guī)范和AMD規(guī)范有什么區(qū)別呢

  1. 運(yùn)行環(huán)境不同汇在,commonjs規(guī)范只能運(yùn)行在node端愿阐,而AMD規(guī)范則被用到瀏覽器端
  2. 由于運(yùn)行環(huán)境的不同,二者的加載機(jī)制也不同趾疚,commonjs中的require是同步執(zhí)行的缨历,而AMD中則是異步的。
  • ES2015模塊化

ES2015中糙麦,可以使用export, export default, import import * as 等操作符來(lái)作模塊化的功能辛孵,但是這個(gè)規(guī)范現(xiàn)在尚未被任何瀏覽器加入規(guī)范中,我目前的Chrome版本為63.0.3239.132赡磅,也無(wú)法原生支持魄缚,不過(guò)現(xiàn)階段我們幾乎都用上了這個(gè)規(guī)范,這一切都只能歸功于babel,webpackrollup等新工具的出現(xiàn)焚廊,既然如此冶匹,那就擁抱未來(lái)吧,不過(guò)有一點(diǎn)咆瘟,需要在了解原理的前提下嚼隘,不然,倘若有一天袒餐,真的需要我們來(lái)封裝一個(gè)小小的模塊的時(shí)候飞蛹,沒(méi)有了那些工具谤狡,我們?cè)搹暮蜗率帜亍?/p>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卧檐,隨后出現(xiàn)的幾起案子墓懂,更是在濱河造成了極大的恐慌,老刑警劉巖霉囚,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捕仔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盈罐,警方通過(guò)查閱死者的電腦和手機(jī)榜跌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)暖呕,“玉大人,你說(shuō)我怎么就攤上這事苞氮⊥謇浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵笼吟,是天一觀的道長(zhǎng)库物。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贷帮,這世上最難降的妖魔是什么戚揭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮撵枢,結(jié)果婚禮上民晒,老公的妹妹穿的比我還像新娘。我一直安慰自己锄禽,他們只是感情好潜必,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著沃但,像睡著了一般磁滚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宵晚,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天垂攘,我揣著相機(jī)與錄音,去河邊找鬼淤刃。 笑死晒他,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逸贾。 我是一名探鬼主播仪芒,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼唁影,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了掂名?” 一聲冷哼從身側(cè)響起据沈,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饺蔑,沒(méi)想到半個(gè)月后锌介,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猾警,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年孔祸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片发皿。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡崔慧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出穴墅,到底是詐尸還是另有隱情惶室,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布玄货,位于F島的核電站皇钞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏松捉。R本人自食惡果不足惜夹界,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望隘世。 院中可真熱鬧可柿,春花似錦、人聲如沸丙者。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔓钟。三九已至永票,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滥沫,已是汗流浹背侣集。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兰绣,地道東北人世分。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像缀辩,于是被迫代替她去往敵國(guó)和親臭埋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子踪央,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 原文鏈接:http://www.cnblogs.com/lvdabao/p/js-modules-develop....
    舌尖上的大胖閱讀 698評(píng)論 0 1
  • 什么是模塊化開(kāi)發(fā)? 前端開(kāi)發(fā)中瓢阴,起初只要在script標(biāo)簽中嵌入幾十上百行代碼就能實(shí)現(xiàn)一些基本的交互效果畅蹂,后來(lái)js...
    半世韶華憶闌珊閱讀 650評(píng)論 0 0
  • 模塊通常是指編程語(yǔ)言所提供的代碼組織機(jī)制,利用此機(jī)制可將程序拆解為獨(dú)立且通用的代碼單元荣恐。所謂模塊化主要是解決代碼分...
    MapleLeafFall閱讀 1,165評(píng)論 0 0
  • ## 前言 The Module Pattern液斜,模塊模式,也譯為模組模式叠穆,是一種通用的對(duì)代碼進(jìn)行模塊化組織與定義...
    b2e16cc43137閱讀 3,014評(píng)論 1 4
  • 似曾相識(shí)這透明體少漆, 一片片智慧飄落紅塵, 靈凈硼被、慈善示损。那寂寥無(wú)聲的遺落, 是為了告知世人它的智慧凄冷孤寂不在時(shí)空轄...
    紅箭閱讀 305評(píng)論 0 0