淺談 JavaScript 模組化:從 IIFE 到 ES Modules 的進化

更新 發佈閱讀 10 分鐘
JavaScript 一開始是為了在網頁中加入互動效果而設計的腳本語言,隨著功能需求越來越複雜,程式碼的結構與可維護性也變得越來越重要。
這就是「模組化(Modularization)」誕生的背景。

🐻為什麼需要模組化?

早期的 JavaScript 開發常把所有程式碼寫在同一個 .js 檔案中,變數與函式都是全域的(global),這樣做會導致:

  • 命名衝突:不同功能可能使用相同變數名稱而互相干擾。
  • 可讀性差:所有邏輯糾結在一起,不容易閱讀與維護。
  • 測試困難:函式間高度耦合,無法單獨測試。

模組化的核心目標是 將程式碼依照功能切分為獨立單元,彼此之間低耦合高內聚,方便重複使用、測試與維護。

🐻常見的模組化方式

IIFE(Immediately Invoked Function Expression)

  • 最早期的模組化技巧,用來隔離變數作用域。
  • 使用函式包住程式碼,並立即執行。

模組定義:

// greet-iife.js
(function () {
const name = "IT熊";

function sayHello() {
console.log(`Hello, ${name}`);
}

// 模擬暴露給外部
window.greet = {
sayHello
};
})();

呼叫方式:

<script src="greet-iife.js"></script>
<script>
greet.sayHello(); // 輸出: Hello, IT熊
</script>

優點:

  • 解決全域命名污染問題。
  • 實現「私有變數」的效果。

缺點:

  • 沒有真正的模組系統,模組間的依賴要手動管理。
  • 結構不夠清晰,容易產生技術債。

適用情境:

  • 老舊專案、沒有模組工具的純前端網頁。

CommonJS(Node.js 預設模組系統)

  • 每個 .js 文件就是一個模組。
  • 使用 require() 載入模組,使用 module.exports 輸出。

模組定義:

// greet-commonjs.js
const name = "IT熊";

function sayHello() {
console.log(`Hello, ${name}`);
}

module.exports = {
sayHello
};

呼叫方式:

// main.js (Node.js 執行環境)
const greet = require('./greet-commonjs.js');

greet.sayHello(); // 輸出: Hello, IT熊

優點:

  • 模組語法簡單直觀。
  • Node.js 生態系完整,NPM 模組幾乎都是用 CommonJS 撰寫。

缺點:

  • 同步載入:在瀏覽器中不適用,會阻塞執行。
  • 無法靜態分析(例如 Tree Shaking)。

適用情境:

  • Node.js 應用程式,如 CLI 工具、伺服器端程式。

AMD(Asynchronous Module Definition)

  • 為瀏覽器設計的模組規範,支援非同步載入。
  • 使用 define()require(),代表工具為 RequireJS

模組定義:

// greet-amd.js
define([], function () {
const name = "IT熊";

function sayHello() {
console.log(`Hello, ${name}`);
}

return {
sayHello
};
});

呼叫方式:

<!-- 引入 RequireJS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
<script>
require(['greet-amd'], function (greet) {
greet.sayHello(); // 輸出: Hello, IT熊
});
</script>

優點:

  • 支援非同步載入模組,適合瀏覽器端資源管理。

缺點:

  • 語法繁瑣、學習曲線高。
  • 現代開發工具(如 Webpack)幾乎取代其功能。

適用情境:

  • 舊專案、RequireJS 建立的大型單頁應用(SPA)。

UMD(Universal Module Definition)

  • 結合 CommonJS、AMD、與全域變數的模組定義方式。
  • 可同時在 Node.js、RequireJS、瀏覽器環境運作。

模組定義:

// greet-umd.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory); // AMD
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(); // CommonJS
} else {
root.greet = factory(); // Global
}
}(this, function () {
const name = "IT熊";

function sayHello() {
console.log(`Hello, ${name}`);
}

return {
sayHello
};
}));

呼叫方式:

(取決於環境)

在 HTML 中:

<script src="greet-umd.js"></script>
<script>
greet.sayHello(); // 輸出: Hello, IT熊
</script>

在 Node.js 中:

const greet = require('./greet-umd.js');
greet.sayHello(); // 輸出: Hello, IT熊

優點:

  • 極高的相容性,適合開源函式庫發佈。

缺點:

  • 編寫複雜,一般專案不需自行撰寫,通常透過工具產出。

適用情境:

  • 跨平台函式庫 或 SDK(如 jQuery、Lodash 發佈格式)。

ES Modules(ESM,現代標準模組)

  • 自 ES2015(ES6)起加入的原生模組語法。
  • 使用 importexport,支援靜態分析與 Tree Shaking。

模組定義:

// greet-esm.js
const name = "IT熊";

export function sayHello() {
console.log(`Hello, ${name}`);
}

呼叫方式:

(取決於環境)

在 HTML 中:

<!-- 注意 type="module" -->
<script type="module">
import { sayHello } from './greet-esm.js';

sayHello(); // 輸出: Hello, IT熊
</script>

在 Node.js 中(package.json 中加 "type": "module"[註1]):

// main.mjs
import { sayHello } from './greet-esm.js';

sayHello(); // 輸出: Hello, IT熊

優點:

  • 標準語法,瀏覽器與 Node.js 都支援。
  • 最佳效能,支援靜態分析與懶加載。
  • 與打包工具(Webpack、Vite、Rollup)高度整合。

缺點:

  • 較新的 Node.js 版本(>= 12)才全面支援。
  • 若用在瀏覽器,需透過 type="module" 並處理 CORS 限制。

適用情境:

  • 現代前端專案、React/Vue/Angular 應用程式、Node.js + ES 模組開發。

🐻模組化帶來什麼好處?

  • 提升可維護性:功能單一的模組易於管理與除錯。
  • 加速開發:多人協作時,各自負責不同模組。
  • 提升效能:搭配打包工具(如 Webpack, Vite),能進行模組載入優化。
  • 利於測試:模組化讓單元測試變得簡單。

🐻結語

模組化讓 JavaScript 從混亂走向秩序,是現代開發中不可或缺的觀念。無論你是前端工程師、Node.js 開發者,還是剛入門的學習者,了解模組化都能讓你的程式碼更具結構、更易維護。

🐻備註

[1] Node.js 一開始是用 CommonJS 作為模組系統(使用 require/module.exports),直到後來才開始支援 ES Modules(使用 import/export),但預設情況下仍是用 CommonJS。所以要在 Node.js 中使用 ES Modules 語法,就必須告訴 Node.js:「我要用 ESM!」

這就是為什麼你要在 package.json 裡加:

{
"name": "my-esm-project",
"type": "module"
}
留言
avatar-img
留言分享你的想法!
avatar-img
IT熊的沙龍
0會員
4內容數
IT熊的沙龍是一個結合技術、創意與交流的空間,由熱愛程式與分享的「IT熊」主持。在這裡,你會看到最新的開發趨勢、實用的程式技巧、深入的技術解析,以及職涯與生活的輕鬆對談。 無論你是剛踏入程式世界的新手,還是經驗豐富的工程師,都歡迎進入 IT熊的沙龍,一起學習、分享、成長。
你可能也想看
Thumbnail
建立自己的Module有哪些好處?
Thumbnail
建立自己的Module有哪些好處?
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
TypeScript是一種由Microsoft開發和維護的開源編程語言。它是JavaScript的超集,主要擴展了JavaScript的語法,增加了靜態類型檢查和其他特性,使得開發大型應用程序更為方便和可靠。
Thumbnail
TypeScript是一種由Microsoft開發和維護的開源編程語言。它是JavaScript的超集,主要擴展了JavaScript的語法,增加了靜態類型檢查和其他特性,使得開發大型應用程序更為方便和可靠。
Thumbnail
JavaScript (簡稱 JS) 是具有一級函數的輕量級、直譯式或即時編譯的程式語言。它因為用作網頁的腳本語言而大為知名,但也用於許多非瀏覽器的環境,像是 Node.js 等。由於 JavaScript 語法上的一些缺點,軟體工程師們又設計出了 CoffeeScript、TypeScript 和
Thumbnail
JavaScript (簡稱 JS) 是具有一級函數的輕量級、直譯式或即時編譯的程式語言。它因為用作網頁的腳本語言而大為知名,但也用於許多非瀏覽器的環境,像是 Node.js 等。由於 JavaScript 語法上的一些缺點,軟體工程師們又設計出了 CoffeeScript、TypeScript 和
Thumbnail
樣板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
Thumbnail
樣板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
Thumbnail
JavaScript是一種具有動態型別、弱型別、原型繼承等特性的高級腳本語言,應用範圍廣泛,包括前端開發、後端開發、移動應用等。它被各種公司和開源社區廣泛使用。學習JavaScript需要掌握ECMAScript標準、異步編程、模塊系統等知識。
Thumbnail
JavaScript是一種具有動態型別、弱型別、原型繼承等特性的高級腳本語言,應用範圍廣泛,包括前端開發、後端開發、移動應用等。它被各種公司和開源社區廣泛使用。學習JavaScript需要掌握ECMAScript標準、異步編程、模塊系統等知識。
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
類別 (class) 是在 ES6 中引入,用來作為建立新物件的模板。它可以將程式碼封裝起來。
Thumbnail
類別 (class) 是在 ES6 中引入,用來作為建立新物件的模板。它可以將程式碼封裝起來。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News