目前主流的JavaScript模塊化實現(xiàn)的技術(shù)以及它們之間的區(qū)別。

目前主流的JavaScript模塊有CommonJS、AMD、CMD、以及ES的模塊系統(tǒng)。

一、CommonJS

commonJS的出發(fā)點:js沒有完善的模塊系統(tǒng),但是隨著NodeJS的出現(xiàn),讓js可以在任意地方運行,因此具備了大型項目的開發(fā)能力,CommonJS也在此時應(yīng)運而生。
NodeJS是commonJS的主要實踐者,有四個環(huán)境變量Module,exports,require,global為它提供支持,實際使用時,用module.exports導(dǎo)出模塊(定義當前模塊對外輸出的接口),require加載模塊。

commonJS使用同步的方式加載模塊,在本地時,因為模塊文件儲存在磁盤中,讀取速度很快,所以沒有問題,但是在瀏覽器中,因為網(wǎng)絡(luò)的問題,所以更合理的方法是采用異步的方法。
-暴露方法>module.exports = value或exports.xxx = value
-引入模塊>const xxx = require(xxx)

commonJS規(guī)范
1.一個文件就是一個模塊,具有單獨的作用域。
2.普通方式定義的變量、函數(shù)、對象都屬于該作用域中。
3.通過require加載模塊。
4.通過exports和module.exports來暴露模塊中的內(nèi)容。
注意:
1.exports是module.exports的子集
2.所有代碼運行在指定的模塊中,不會污染全局作用域
3.模塊可以被多次加載,但是只會在第一次加載時執(zhí)行,之后就會講運行結(jié)果緩存進行下一次使用。
4.模塊加載順序,按照模塊出現(xiàn)的順序進行加載。
5._dirname代表當前文件所在的文件夾路徑
6._filename代表當前模塊文件所在的文件夾路徑+文件名
7.當exports和module.exports同時存在,module.exports會覆蓋exports。
8.當模塊內(nèi)全是exports時,就相當于module.exports

二、ES6模塊化

es6模塊化語言旨在成為瀏覽器和服務(wù)器的通用模塊解決方案,通過export導(dǎo)出模塊,通過import引入模塊,es6還提供了默認導(dǎo)出的exports default命令,為模塊增加指定輸出,對應(yīng)的import不需要大括號。
es6模塊不是對象,import命令會被js引擎靜態(tài)分析(安全的編譯,優(yōu)化性能,靜態(tài)的將代碼加載到引用了的文件?具體不太懂,了解清楚后會發(fā)文),編譯時就會引入模塊的代碼,而不是在代碼運行的時候去加載,所以無法實現(xiàn)按條件加載。也正是因為這個,使靜態(tài)加載成為可能。
1.export 將模塊中的代碼對外暴露,可以導(dǎo)出的是一個對象包含的多個屬性方法,export.default只能導(dǎo)出一個可以不具名的函數(shù),我沒可以通過import引用,同時我沒也可以用require引入,因為webpack引起了server相關(guān)。
2.import 引入需要用到的模塊,在編譯時就會引入,所以不存在按需引入。

import {fn} from './xxx/xxx'(export的導(dǎo)出方式的引用方式)
import fn from './xxx/xxx1'(export.default的到處方式的引用方式)

三、AMD

Asynchronous Module Definition,異步加載模塊。它是一個在瀏覽器端模塊化開發(fā)的規(guī)范,不是原生js的規(guī)范,使用AMD進行模塊開發(fā)需要使用到RequireJS函數(shù)庫。
AMD規(guī)范采用異步方式加載模塊,模塊的加載不影響后續(xù)代碼的執(zhí)行,所有依賴這個模塊的語句都會定義一個回調(diào)函數(shù),當模塊加載完成后會執(zhí)行這個回調(diào)函數(shù)。
使用require.js實現(xiàn)AMD規(guī)范的模塊化:用require.config()指定引用路徑等,用defined()定義模塊,用require()引入模塊。

//定義模塊
defined('moduleName',['a','b'],function(ma,mb){
  return someExportValue
})  
//引入模塊
require(['a','b'],function(ma,mb)){
  //*code*
}

1.函數(shù)庫requireJS主要解決的問題
-文件可能存在依賴關(guān)系,被依賴的文件需要早于依賴它的文件加載到瀏覽器中。
-js在加載的時候瀏覽器會停止頁面渲染,加載文件越多,頁面的響應(yīng)時間就會越長。
-異步加載前置
2.語法
define(id,dependencies,factory)
-id 可選參數(shù),用來定義模塊的標識,如果沒有提供該參數(shù),將使用腳本文件名(去掉拓展名)
-dependencies是一個當前模塊用來的模塊名稱數(shù)組。
-factory,工廠方法,模塊初始化要執(zhí)行的函數(shù)或是對象,如果是函數(shù),他應(yīng)該制備執(zhí)行一次,如果是對象,此對象應(yīng)該為模塊的輸出值。

四、CMD

CMD是另一種js模塊化方案,它與AMD很類似,不同點在于:AMD推崇依賴前置、提前執(zhí)行,CMD推崇依賴就近、延遲執(zhí)行。此規(guī)范其實是在sea.js推廣過程中產(chǎn)生的。
因為CMD推從一個文件一個模塊,所以經(jīng)常就用文件名作為模塊id;CMD推推崇依賴就近,所以一般不再define的參數(shù)中寫依賴,而是在factory中寫
define(id,deps,factory)
factory有三個參數(shù):function(require,exports,module){}
1.require參數(shù)是第一個參數(shù),是一個方法,接收模塊標識作為唯一參數(shù),用來獲取其它模塊提供的接口;
2.exports,是一個對象,用來向外提供模塊接口;
3.module,是一個對象,上面存儲了與當前模塊相關(guān)聯(lián)的一些屬性和方法。

//定義沒有依賴的模塊
define(function(require,exports,module){
  exports.xxx = value
module.exports = value
})
//定義有依賴的模塊
define(function(require,exports,module){
  //同步引入模塊
  var module1 = require('./module1.js')
  //異步引入模塊
  require.async('./module2.js',function(m2){
  /***/
})
exports.xxx = value
}
//引入模塊
define(function(require){
  const m1 = require('./module1.js');
m1.show()
})

五UMD通用模塊規(guī)范

一種整合了CommonJS和AMD規(guī)范的方法,希望能解決跨平臺模塊方案。
運行原理
-UMD先判斷是否支持Node.js模塊(exports是否存在),存在則用Node.js模塊模式。
-在判斷是否支持AMD(define是否存在)存在則使用AMD加載模塊。

(function (window, factory) {
    if (typeof exports === 'object') {  
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {    
        window.eventUtil = factory();
    }
})(this, function () {
    //module ...
});

六、總結(jié)

commonjs是同步加載的,主要是在nodejs也就是服務(wù)端應(yīng)用的模塊化機制,通過Module.export導(dǎo)出聲明。通過require('')加載。每個文件都是一個模塊。他有自己的作用域,文件內(nèi)的變量,屬性函數(shù)等不能被外界訪問。node會將模塊緩存,第二次加載會直接在緩存中獲取。
AMD是異步加載的。主要應(yīng)用在瀏覽器環(huán)境下,requireJS是遵循AMD規(guī)范的模塊化工具,他是通過define()定義聲明,通過require('',function(){})加載。

es6的模塊化加載時通過export default導(dǎo)出,用import帶入,可通過{}對導(dǎo)出的內(nèi)容進行解構(gòu)。

es6的模塊的運行機制與common不一樣,js引擎對腳本靜態(tài)分析的時候,遇到模塊加載指令后會生成一個只讀引用,等到腳本真正執(zhí)行的時候才會通過引用去模塊中獲取值,在引用到執(zhí)行的過程中,模塊中的值發(fā)生了變化,導(dǎo)入的這里也會跟著變,es6
模塊是動態(tài)引用,并不會緩存值。模塊里總是綁定其所在的模塊。

關(guān)于模塊化,我認為是構(gòu)建大型項目所必須的,讓代碼結(jié)構(gòu)更加清晰,讓模塊之間的引用關(guān)系,以及具體作用功能更加清晰,方便了團隊聯(lián)合開發(fā)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容