前端模組化的演變過程

RisingSunBlogs發表於2021-02-04

隨著前端的發展,無模組化存在的問題日益顯露。但在這個過程中,模組化也是有一定的發展。

 stage1-檔案劃分方式

根據業務或功能封裝某一類變數或者函式;

約定每一個檔案都是一個模組;

當使用到這個模組的時候,通過script標籤引入到html頁面中,直接使用模組中的成員(變數|函式);

但當程式碼體積達到一定量的時候,這種方法的缺點就很明顯了。

//module-a.js
// module a 相關狀態資料和功能函式

var name = 'module-a'

function method1 () {
  console.log(name + '#method1')
}

function method2 () {
  console.log(name + '#method2')
}
//module-b.js
// module b 相關狀態資料和功能函式

var name = 'module-b'

function method1 () {
  console.log(name + '#method1')
}

function method2 () {
  console.log(name + '#method2')
}
//index.html
  <script src="module-a.js"></script>
  <script src="module-b.js"></script>
  <script>
    // 命名衝突
    method1()
    // 模組成員可以被修改
    name = 'foo'
  </script>

缺點:

  1. 全部變數都暴露在全域性作用域中,沒有私有空間,所有成員都可被外部訪問或者修改
  2. 當模組達到一定數量,通過約定的方式很難避免變數衝突
  3. 無法管理模組與模組之間的依賴關係

stage2-名稱空間的方式

每個模組只暴露一個全域性物件,所有的成員都掛載到這個全域性物件上

//module-a.js
var moduleA = {
  name: 'module-a',

  method1: function () {
    console.log(this.name + '#method1')
  },

  method2: function () {
    console.log(this.name + '#method2')
  }
}
//module-b.js
var moduleB = {
  name: 'module-b',

  method1: function () {
    console.log(this.name + '#method1')
  },

  method2: function () {
    console.log(this.name + '#method2')
  }
}
//index.html
  <script src="module-a.js"></script>
  <script src="module-b.js"></script>
  <script>
    moduleA.method1()
    moduleB.method1()
    // 模組成員可以被修改
    moduleA.name = 'foo'
  </script>

優點:

     通過“名稱空間”減小了命名衝突的可能

 缺點:

     模組內部的成員依然在外部可以被訪問和修改

     模組之間的依賴關係依然不明確

stage3-通過立即執行函式(IIFE)為模組提供私有空間

具體做法就是將模組內的程式碼放在一個立即執行函式中

若想把某個成員暴露出去,就把該成員掛載到window中

//module-a.js
;(function () {
  var name = 'module-a'
  
  function method1 () {
    console.log(name + '#method1')
  }
  
  function method2 () {
    console.log(name + '#method2')
  }

  window.moduleA = {
    method1: method1,
    method2: method2
  }
})()
//module-b.js
;(function ($) {
  var name = 'module-b'
  
  function method1 () {
    console.log(name + '#method1')
  }
  
  function method2 () {
    console.log(name + '#method2')
  }

  window.moduleB = {
    method1: method1,
    method2: method2
  }
console.log($('#a').html()); })(jQuery)
//index.html
 <script src="module-a.js"></script>
  <script src="module-b.js"></script>
  <script>
    moduleA.method1()
    moduleB.method1()
    // 模組私有成員無法訪問
    console.log(moduleA.name) // => undefined
  </script>

優點:

      實現了成員私有化,模組內的變數外界不能隨意訪問

      通過立即執行函式,可以傳遞該模組所依賴的模組,使模組對外部的依賴更加清晰

小結:綜上所述,隨著模組化的發展,之前所提到的問題也逐一被解決,但還是存在一部分沒有解決的問題。先前所有模組都是通過script標籤引入的。若我們需要某個模組時,通過script標籤引入了該模組,但可能會忘記引入該模組所依賴的模組。或者當我們刪除某個模組時,我們也可能會忘記該模組所依賴的模組。

stage4-模組化規範的出現

     1.CommonJS

        特點:

1.一個檔案就是一個模組

        2.每個模組都有一個單獨的作用域

   3.每個模組暴露出去的成員都由module.exports匯出

        4.使用其他模組的成員時使用require函式匯入

       CommonJS規範主要引用在Node專案中,該規範載入模組時同步載入,倘若用在瀏覽器中,會有大量的同步請求導致應用比較慢,但在Node中不會有問題(因為Node是啟動時載入模組)

    2.AMD規範(Asynchronous Module Definition

       代表庫:require.js

       特點:

       不同於CommonJS的同步載入,該模組可以非同步載入模組,提高程式在瀏覽器的執行效率

       但使用起來相對複雜

    3.CMD規範( Common Module Definition )

       代表庫:Sea.js

       特點:

        使用上類似於require.js,寫法類似於CommonJS,算是個重複的輪子

    4.ES Modules(ES2015的新語法)

       特點:

        語言層面推出的新語法,比較完善

        滿足在web端開發使用模組化的需求

綜上所述:目前前端模組化基本統一成了CommonJS(Node.js)和ES Modules(瀏覽器端開發),我們只需掌握這兩種規範開發即可,後續會對著兩個模組重點展開討論

相關文章