什麼是 Javascript module,讓 JavaScript 代碼更有組織

a computer with a keyboard and mouse

我們可能都很會使用開發 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)標準的一部分;使用 importexport 語句,現代瀏覽器和 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 importexport依賴特定規範,如 CommonJS 的 requiremodule.exports
執行環境現代瀏覽器和最新版本的 Node.js 直接支援多在特定環境(如 Node.js)或需透過轉譯工具在瀏覽器中運行
加載機制支援異步加載,適合大型應用和網頁環境主要用於同步加載
工具依賴不依賴於外部工具或編譯器,簡化設置和部署流程通常需要像 Webpack 或 Babel 這樣的打包工具

現代化的瀏覽器已開始支持原生 javascript module.

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

參考來源:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *