JavaScript模塊的前世今生

jopen 9年前發布 | 27K 次閱讀 JavaScript開發 JavaScript

如今JavaScript模塊化編程的概念已經普及開來,一提起模塊化,大家想到的可能是AMD,CMD,requirejs或seajs。其實還有很多其他的概念。本文將會陳述下JavaScript模塊的前世今生。

眾所周知,JavaScript由于歷史的原因并沒有模塊的概念,自從ajax帶來了web2.0概念后,js代碼已經和以前大不相同了,2009年HTML5興起后,前端代碼的行數已經呈現井噴式發展,隨著代碼量的增加,模塊的缺失的缺點日益凸顯,Javascript社區做了很多探索。

模塊的定義

模塊并非js語言獨創,顯然是借鑒其他語言的,下面是百度百科對模塊的定義:

模塊,又稱構件,是能夠單獨命名并獨立地完成一定功能的程序語句的集合(即程序代碼和數據結構的集合體)

</blockquote>

從中提煉出幾個關鍵字就是,獨立,集合,完成一定功能。

上面的提煉,再從其他語言的實現中借鑒下,總結起來,我們期待的模塊有如下特性:

  • 獨立性——能夠獨立完成一個功能,不受外部環境的影像
  • 完整性——完成一個特定功能
  • 集合性——一組語句的集合
  • 依賴性——可以依賴已經存在的模塊
  • 被依賴——可以被其他模塊依賴
  • </ul>

    其實我們想要的就是一個獨立的模塊,并能引用依賴,及被依賴。

    C語言的庫和頭文件(include),java的包(import)。這在其他語言中都是原生支持的特性,在js中卻是沒有的。

    原始寫法

    如果僅從定義入手,那么一個函數即可成為一個模塊(獨立,集合,完成一個功能),那我們就先從最原始的探索開始,也許不經意間,我們早已在使用模塊了。

    //最簡單的函數,可以稱作一個模塊
    function add(x, y) {
        return x + y;
    }

    稍微了解點javascript基礎的人都知道js中能創建作用域的就是函數(ES6之前),總結下社區的探索,對模塊的模擬大概如下:

    (function (mod, $, _) {
        mod.add = ***;
        mod.sub = ***;
    }((window.mod = window.mod || {}), jQuery, Underscore));

    上面的mod模塊不會重復定義,可自由定義依賴。

    99%的人思想會止步于此,但這種實現其實并不完美,仍然需要手動維護依賴的順序。典型的場景就是上面的jquery必須先于我們的代碼引入,不然會報引用錯誤,這顯然不是我們想要的。

    我在寫Painter的時候,曾經手動維護幾十個script之間的先后順序,這種感覺很虐心,最后想加個新script很容易報錯。下面介紹的

    YUI

    前段時間雅虎宣布YUI不再更新了,很是傷感,最早接觸模塊的概念,當屬YUI了,當然不是YUI2了。

    YUI3經過全新設計,使用了沙箱模式 + 命名空間的方式,并有了模塊的概念。

    例如在YUI3中想使用一個模塊,需要如下這樣:

    //使用node模塊,node模塊會作為參數傳入
    YUI().use('node', function (Y) {
        ///***
    }

    YUI的模塊化已經做的很好了,但對于僅想使用模塊的人,要引入YUI確實有點太重了。

    CMD(Common Module Definition)

    說道CMD就不能不提commonjs,提到commonjs就不能不提node

    CMD規范參照commonjs中的方式,定義模塊的方式如下:

    define(function(require, exports, module) {

    // The module code goes here });</pre>

    一個文件就是一個模塊,文件名就是模塊的名字,使用模塊的方法也和commonjs中一致,只需require就好了,模塊名字可省略后綴。

    //使用event.js模塊
    var ec = require('event');

    CMD的典型實現就是seajs,應用的很廣泛。

    AMD(Asynchronous Module Definition)

    [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)是異步模塊定義,特別適合在瀏覽器端使用,其規范和CMD是很像的,AMD規范中定義模塊的方式如下:

    define(id?, dependencies?, factory);

    同CMD一樣,一個文件即一個模塊,模塊的使用方法如下:

    define(["beta"], function (beta) {
        bata.***//調用模塊
    });

    AMD主張依賴注入,這點和CMD不同(以來查找)。

    AMD也支持已CMD的方式來使用依賴。

    AMD的典型實現有requireJSmodJSlodJS

    KMD

    KMD是kissy中提出來的,是kissy自己的一套模塊化方案,具體我也不是很清楚,感興趣的同學可自行搜索相關資料。

    有一次同事@eric曦堯無意說起,KMD的意思是 kill amd and cmd,當時覺得好高打上的名字(/ □ \)。

    ES6

    ES6帶來了語言層面的模塊化支持,規范方面見這里,文檔方面見這里

    我們現在期待的就是ES6規范快點塵埃落定(據說今年夏天),現在還處于草案狀態,還有瀏覽器廠商們的大力支持,還有就是在國內盡快普及開來。

    UMD

    UMD的全稱是Universal Module Definition。和它名字的意思一樣,這種規范基本上可以在任何一個模塊環境中工作。

    一段典型的UMD代碼如下所示:

    (function (root, factory) {
        var Data = factory(root);
        if ( typeof define === 'function' && define.amd) {
            // AMD
            define('data', function() {
                return Data;
            });
        } else if ( typeof exports === 'object') {
            // Node.js
            module.exports = Data;
        } else {
            // Browser globals
            var _Data = root.Data;

        Data.noConflict = function () {
            if (root.Data === Data) {
                root.Data = _Data;
            }
    
            return Data;
        };
        root.Data = Data;
    }
    

    }(this, function (root) { var Data = ... //自己的代碼 return Data; }));</pre>

    這是出自data.js中的一部分代碼,其原理就是做個判斷,不同的環境進行不同的處理。

    我已將UMD應用到自己的項目中,瞬間感覺高大上了不少:-)。

    總結

    比較成氣候的模塊化方案,當屬AMD和CMD,網上關于二者比較的文章甚多,很難評價誰好誰壞,當下開來AMD的使用范圍似乎更廣些,而CMD的本土化方面做的更好。

    這些模塊化的探索,使前端工程化成為了可能,可以說沒有模塊,工程化更無從彈起,本文總結了大家在模塊化方面的一些探索,下一篇文章將重點介紹下lodJS(一款基于AMD的模塊加載器)的實踐和原理。

    參考資料

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!