Table of Contents
我們可能都很會使用開發 node.js 程式,使用各種前端工具,但可能不是很了解什麼是 Javascript module、ES modules、CommonJS Module,又為什麼有些程式使用 require?有些程式使用 import ?
網頁開發的早期挑戰
在 JavaScript 模組成為標準之前,開發大型網頁應用程式是一項相當複雜的任務。當時開發者面臨許多挑戰:
全域命名空間污染
命名衝突: 所有 JavaScript 變數和函數默認在全域命名空間中。這導致了命名衝突,特別是在使用多個腳本時。
維護困難: 隨著代碼庫的增長,找出命名衝突的源頭變得越來越困難。
依賴管理的挑戰
手動管理: 開發者需要手動管理腳本之間的依賴關係,確保它們以正確的順序加載。
性能問題: 隨著腳本數量的增加,網頁加載時間增長,影響用戶體驗。
重複代碼
重複性工作: 缺乏模組化導致代碼重複,特別是在大型團隊或多個項目中。
為了應對這些挑戰,開發者們採用了不同的策略:
立即調用函數表達式(IIFE): 用於創建局部作用域,避免全域變數污染。
命名空間模式: 通過創建一個全域對象來存儲所有功能和變數,減少全域變數的數量。
但這些方式在專案範圍擴大時,也變的窒礙難行,所以漸漸開始有在前端引入模組的想法出現。
JavaScript 模組的本質
在 JavaScript 的世界中,模組就像是應用程式的樂高積木,它們透過將程式碼分解成更小、可重複使用的部分,幫助組織和管理程式碼。
所有這些模組系統都有一個共同點: 它們允許您導入和導出內容。
模組化程式碼: 將模組視為個別的腳本檔案,每個模組封裝特定的功能或一組相關功能。
範圍和封裝: 模組有助於封裝程式碼。除非明確導出,否則模組中的變數和函數對其他模組不可見。
假設有一個用於實用功能的模組(utils.js
):
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
然後可在另一個模組中使用這些函數(main.js
):
// main.js
import { add, subtract } from './utils.js';
console.log(add(5, 3)); // 輸出:8
console.log(subtract(5, 3)); // 輸出:2
使用模組自然會產生諸多設計上的優點:
可維護性: 將複雜的程式碼分解成易於管理的部分。
可重用性: 允許在應用程式的不同部分重複使用程式碼。
命名空間管理: 減少全局命名空間污染,最小化衝突。
依賴性管理: 明確定義程式碼各部分之間的依賴關係。
現代 JavaScript 模組的類型
CommonJS 模組
非原生 JavaScript 模組,在 ES6 模組標準之前,JavaScript 沒有內建的模組系統,非原生模組是透過各種工具和規範實現。
類型包括 CommonJS(Node.js 中使用)、AMD(Asynchronous Module Definition)、UMD(Universal Module Definition)等。
主要通過工具如 Webpack 或 Babel 轉譯或封裝,以支援模組化,使用 require()
進行導入和 module.exports
進行導出。
範例:
// CommonJS 模組的導出
module.exports = {
sayHello: function(name) {
return `Hello, ${name}!`;
}
};
// 導入
const { sayHello } = require('./module');
ECMAScript(ES)模組
原生 JavaScript 模組(也稱為 ECMAScript 模組或 ES 模組)是 ECMAScript 2015 (ES6)標準的一部分;使用 import
和 export
語句,現代瀏覽器和 Node.js 都已開始原生支持。
範例:
// 導出
export function sayHello(name) {
return `Hello, ${name}!`;
}
// 導入
import { sayHello } from './module.js';
模組程式和一般的 javascript 程式放在瀏覽器執行時,還一個很重要的差異:
<script src="classic.js"></script>
<script src="classic.js"></script>
<!-- 引入程式會執行多次 -->
<script type="module" src="module.js"></script>
<script type="module" src="module.js"></script>
<script type="module">import './module.js';</script>
<!-- 模組只會執行一次 -->
原生與非原生的比較
特性 | 原生 JavaScript 模組 | 非原生 JavaScript 模組 |
---|---|---|
語法 | 使用 ES6 import 和 export | 依賴特定規範,如 CommonJS 的 require 和 module.exports |
執行環境 | 現代瀏覽器和最新版本的 Node.js 直接支援 | 多在特定環境(如 Node.js)或需透過轉譯工具在瀏覽器中運行 |
加載機制 | 支援異步加載,適合大型應用和網頁環境 | 主要用於同步加載 |
工具依賴 | 不依賴於外部工具或編譯器,簡化設置和部署流程 | 通常需要像 Webpack 或 Babel 這樣的打包工具 |
現代化的瀏覽器已開始支持原生 javascript module.


透過以上簡短說明,應該就能基本了解什麼是 Javascript module,接下來能更認識什麼是 Webpack 打包工具,更能充分使用 Vite 這類更現代化的前端開發工具。
參考來源: