CommonJS 與 ES Module 的區別
- 1194字
- 6分鐘
- 2024-09-09
在 JavaScript 開發中,模組化系統扮演著重要角色,它幫助我們管理和組織代碼。CommonJS 和 ES Module 是兩種主要的模組化標準,它們在模組的加載、導出機制和兼容性等方面存在顯著區別。本文將詳細比較這兩種模組系統的主要特點和區別。
1. 模組加載方式
CommonJS:
-
同步加載:CommonJS 採用同步加載模組的方式。這意味著當使用
require()
函數時,模組會立即加載和執行。這種方式在伺服器端(如 Node.js)非常合適,但在瀏覽器環境中可能導致性能問題,因為瀏覽器需要在模組加載完成後才能繼續執行後續代碼。1// 導入模組2const math = require("./math");3console.log(math.add(2, 3));
ES Module:
-
靜態和異步加載:ES Module 支援靜態和異步加載。模組的導入在編譯階段靜態分析,這允許 JavaScript 引擎進行優化。ES Module 支援通過
import
語法進行異步加載(使用動態import()
),這在瀏覽器環境中尤為重要。1// 靜態導入2import { add } from "./math.js";3console.log(add(2, 3));45// 動態導入6import("./math.js").then((module) => {7console.log(module.add(2, 3));8});
2. 模組導出和導入
CommonJS:
-
模組導出:使用
module.exports
或exports
對象來導出模組的功能。可以導出對象、函數或其他值。1// 導出模組2module.exports = {3add: function (a, b) {4return a + b;5},6}; -
模組導入:使用
require()
函數來導入模組。1// 導入模組2const math = require("./math");3console.log(math.add(2, 3));
ES Module:
-
模組導出:使用
export
關鍵字來導出模組的功能,支援命名導出和預設導出。1// 命名導出2export function add(a, b) {3return a + b;4}56// 預設導出7export default function add(a, b) {8return a + b;9} -
模組導入:使用
import
關鍵字來導入模組,支援導入模組的一部分或整個模組。1// 導入命名導出2import { add } from "./math.js";3console.log(add(2, 3));45// 導入預設導出6import add from "./math.js";7console.log(add(2, 3));
3. 模組解析
CommonJS:
-
動態解析:模組路徑是動態解析的,可以在代碼運行時計算模組路徑。這使得條件導入或動態加載模組變得可能。
1const math = require("./math-" + someCondition + ".js");
ES Module:
-
靜態解析:模組路徑在編譯階段靜態解析,編譯器可以在代碼運行之前確定依賴關係。這使得靜態分析和優化變得可能,但不支援動態解析路徑。
1import { add } from "./math.js";
4. 兼容性
CommonJS:
- 主要用於 Node.js:CommonJS 是 Node.js 的預設模組系統,瀏覽器環境不直接支援 CommonJS 模組,但可以通過工具如 Browserify 或 Webpack 來使用 CommonJS 模組。
ES Module:
- 標準化:ES Module 是 ECMAScript 標準的一部分,現代瀏覽器和 Node.js 都廣泛支援。它是前端和後端都推薦的模組系統。
5. 運行時行為
CommonJS:
- 動態加載和快取:CommonJS 模組在第一次
require
時加載和執行,隨後快取。對同一個模組的後續require
調用會返回快取中的模組實例。
ES Module:
- 靜態加載和環形依賴:ES Module 支援靜態分析,使得模組的依賴關係可以在編譯階段確定。對於環形依賴,ES Module 允許部分加載,這意味著模組在加載時仍然可以引用其他模組的部分內容。
6. 導出值 vs. 導出引用
CommonJS:
-
導出值是拷貝:CommonJS 中,模組導出的值是導出對象的一個拷貝。修改導出的對象不會影響其他模組中看到的值。
math.js 1let count = 0;23module.exports = {4add: function (a, b) {5return a + b;6},7getCount: function () {8return count;9},10};1112// app.js13const math = require("./math");14console.log(math.getCount()); // 輸出: 015math.count = 10; // 不會改變 math.getCount() 返回值16console.log(math.getCount()); // 仍然輸出: 0
ES Module:
-
導出值是引用:ES Module 中,模組導出的值是對原始對象的引用。對導出對象的修改會在其他模組中反映出來。
math.js 1export let count = 0;23export function add(a, b) {4return a + b;5}67// app.js8import { count, add } from "./math.js";9console.log(count); // 輸出: 010count = 10; // 會改變 math.js 中的 count11import { count as newCount } from "./math.js";12console.log(newCount); // 仍然輸出: 10
結論
- CommonJS 適合伺服器端(Node.js)使用,其模組以同步方式載入,簡單易用,但在瀏覽器環境中需要額外的工具支援。
- ES Module 是 ECMAScript 的標準模組系統,支持靜態分析和優化,適合現代瀏覽器和 Node.js,具有更好的性能和靈活性。
選擇適合的模組系統可以幫助提高代碼的可維護性和性能,根據專案需求和環境進行選擇是至關重要的。