這一次,我要弄懂javascript的模塊化

      隨着前端js代碼複雜度的提升,js模塊化是必然趨勢,不只好維護,同時依賴很明確,不會全局污染,今天整理一下模塊化的幾個規範吧~html

     首先梳理一下模塊化的發展狀況~

無模塊化-->CommonJS規範-->AMD規範-->CMD規範-->ES6模塊化

1. 無模塊化

     script標籤引入js文件,相互羅列,可是被依賴的放在前面,不然使用就會報錯。以下:前端

<script src="jquery.js"></script>
  <script src="jquery_scroller.js"></script>
  <script src="main.js"></script>
  <script src="other1.js"></script>
  <script src="other2.js"></script>
  <script src="other3.js"></script>複製代碼

      即簡單的將全部的js文件通通放在一塊兒。可是這些文件的順序還不能出錯,好比jquery須要先引入,才能引入jquery插件,才能在其餘的文件中使用jquery。缺點很明顯:
node

  • 污染全局做用域
  • 維護成本高
  • 依賴關係不明顯

2. CommonJS規範

      該規範最初是用在服務器端的node的,它有四個重要的環境變量爲模塊化的實現提供支持:moduleexportsrequireglobal。實際使用時,用module.exports定義當前模塊對外輸出的接口(不推薦直接用exports),用require加載模塊(同步)。jquery

// a-commonJs.js (導出)
var a = 5;var add = function(param){//在這裏寫上須要向外暴露的函數、變量    return a + param}module.exports.a = a;module.exports.add = add===========================
// b-commonJs.js引用自定義模塊,參數包含路徑,可省略.js(導入)
var addFn = require('./a-commonJs')console.log(addFn.add(3)) //8console.log(addFn.a) //5複製代碼

 一點說明:     es6

exports 是對 module.exports 的引用。好比咱們能夠認爲在一個模塊的頂部有這句代碼:   exports = module.exports因此,咱們不能直接給exports賦值,好比number、function等。 複製代碼

注意:由於module.exports自己就是一個對象,因此,咱們在導出時可使用 瀏覽器

module.exports = {foo: 'bar'}  //true緩存

module.exports.foo = 'bar'  //truebash

可是, exports 是 module.exports 的一個引用,或者理解爲exports是一個指針,exports指向module.exports,這樣,咱們就只能使用 exports.foo = 'bar' 的方式,而不能使用服務器

exports = {foo: 'bar'} //error 這種方式是錯誤的,至關於從新定義了exportsbabel

一點優勢:解決了依賴、全局變量污染的問題

一點缺點: CommonJS用同步的方式加載模塊。在服務端,模塊文件都存在本地磁盤,讀取很是快,因此這樣作不會有問題。可是在瀏覽器端,限於網絡緣由,CommonJS不適合瀏覽器端模塊加載,更合理的方案是使用異步加載,好比下邊AMD規範。

3. AMD規範

承接上文,AMD規範則是非同步加載模塊容許指定回調函數,AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。

AMD標準中,定義了下面三個API:

  1. require([module], callback)
  2. define(id, [depends], callback)
  3. require.config()

即經過define來定義一個模塊,而後使用require來加載一個模塊, 使用require.config()指定引用路徑。

先到require.js官網下載最新版本,而後引入到頁面,以下:

<script data-main="./alert" src="./require.js"></script>

data-main屬性不能省略。



以上分別是定義模塊,引用模塊,運行在瀏覽器彈出提示信息。

      引用模塊的時候,咱們將模塊名放在[]中做爲reqiure()的第一參數;若是咱們定義的模塊自己也依賴其餘模塊,那就須要將它們放在[]中做爲define()的第一參數。

     在使用require.js的時候,咱們必需要提早加載全部的依賴,而後纔可使用,而不是須要使用時再加載。

一點優勢:適合在瀏覽器環境中異步加載模塊、並行加載多個模塊

一點缺點:不能按需加載、開發成本大

4. CMD

      AMD 推崇依賴前置、提早執行CMD推崇依賴就近、延遲執行。CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。


很明顯,CMD是按需加載,就近原則。

5. ES6模塊化

      在ES6中,咱們可使用 import 關鍵字引入模塊,經過 exprot 關鍵字導出模塊,功能較之於前幾個方案更爲強大,也是咱們所推崇的,可是因爲ES6目前沒法在瀏覽器中執行,因此,咱們只能經過babel將不被支持的import編譯爲當前受到普遍支持的 require。 


      es6在導出的時候有一個默認導出,export default,使用它導出後,在import的時候,不須要加上{},模塊名字能夠隨意起。該名字實際上就是個對象,包含導出模塊裏面的函數或者變量。


可是一個模塊只能有一個export default

6. CommonJs和ES6區別

如下引用阮一峯老師的內容:

(1) CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。

  • CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。
  • ES6 模塊的運行機制與 CommonJS 不同。JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊裏面去取值。換句話說,ES6 的import有點像 Unix 系統的「符號鏈接」,原始值變了,import加載的值也會跟着變。所以,ES6 模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。

(2) CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。

  • 運行時加載: CommonJS 模塊就是對象;即在輸入時是先加載整個模塊,生成一個對象,而後再從這個對象上面讀取方法,這種加載稱爲「運行時加載」。

  • 編譯時加載: ES6 模塊不是對象,而是經過 export 命令顯式指定輸出的代碼,import時採用靜態命令的形式。即在import時能夠指定加載某個輸出值,而不是加載整個模塊,這種加載稱爲「編譯時加載」。

CommonJS 加載的是一個對象(即module.exports屬性),該對象只有在腳本運行完纔會生成。而 ES6 模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。



一點說明:本文只是本身的一點筆記,方便本身記憶和理解。\(^o^)/~

相關文章
相關標籤/搜索