CommonJS 是 JavaScript 的模塊化規范,主要應用于 服務器端環境(尤其是 Node.js),其核心目標是解決代碼組織、依賴管理和作用域隔離問題 。以下是其核心要點:
🔧 一、核心特性
-
同步加載
模塊通過require()
同步加載并執行,后續代碼需等待模塊加載完成后執行,適用于 I/O 快速的服務器環境(如本地文件讀取) 。 -
作用域隔離
每個文件視為獨立模塊,模塊內定義的變量、函數默認私有(不污染全局作用域),僅通過導出接口對外暴露功能 。// math.js const privateVar = 10; // 私有變量 module.exports = { add: (a, b) => a + b + privateVar }; // 導出接口
-
導出與導入語法
- 導出:使用
module.exports
或exports
對象(注:exports
本質是module.exports
的引用) 。// 正確導出(推薦直接賦值 module.exports) module.exports = { add, subtract }; // 或追加屬性(避免 exports 被重寫) exports.add = (a, b) => a + b;
- 導入:通過
require(模塊路徑)
同步加載其他模塊 。const math = require('./math'); console.log(math.add(1, 2)); // 輸出 13(含私有變量值)
- 導出:使用
-
緩存機制
模塊首次加載后被緩存,后續調用require()
直接返回緩存結果,避免重復執行 。可通過delete require.cache[modulePath]
清除緩存強制重新加載。
?? 二、實現原理
-
模塊包裝
Node.js 將模塊代碼包裹在立即執行函數中,注入module
、exports
、require
等變量:(function(exports, require, module, __filename, __dirname) {// 模塊代碼 });
從而實現作用域隔離和局部變量私有化 。
-
路徑解析與加載
require()
根據路徑規則(./
、../
、絕對路徑或核心模塊名)定位文件,按.js
→.json
→.node
順序解析,支持目錄加載(優先找package.json
的main
字段或index.js
) 。 -
循環依賴處理
當模塊 A 依賴 B,B 又依賴 A 時:- B 加載時會獲取 A 的未完成導出對象(此時 A 可能僅執行了部分代碼) 。
- 依賴執行順序影響導出結果(需合理設計代碼結構避免邏輯混亂)。
?? 三、局限性與適用場景
場景 | 優勢 | 局限性 |
---|---|---|
服務器端 | 同步加載無阻塞,代碼簡潔易維護 | 不適用于瀏覽器(網絡請求阻塞) |
模塊復用 | 清晰的依賴管理,避免全局污染 | 動態導入導致靜態分析困難 |
生態兼容 | Node.js 原生支持,生態成熟 | 瀏覽器端需編譯工具轉換(如 Webpack) |
🔄 四、演進與現狀
- 歷史地位:CommonJS 填補了服務端 JavaScript 模塊化的空白,成為 Node.js 的基石 。
- 現代替代:ES Modules(ESM)憑借靜態分析、異步加載等優勢成為語言標準,逐步取代 CommonJS 。
- 過渡方案:Node.js 支持
.mjs
擴展名或package.json
的"type": "module"
啟用 ESM,同時兼容 CommonJS 語法 。
💡 總結:CommonJS 是服務器端模塊化的經典方案,其同步加載、閉包隔離和緩存機制高效支撐了 Node.js 生態,但瀏覽器兼容性不足推動 ESM 成為未來主流 。