JS模塊化開發(fā)之EsModule和Common.js區(qū)別
1. 語法(Import/Export vs Require/Exports)
ESM 使用 靜態(tài)的 import 和 export,而 CommonJS 使用 動態(tài)的 require 和 module.exports。
ESModule使用 import 和 export 語法來導(dǎo)入和導(dǎo)出模塊。
導(dǎo)入:
import { functionName } from './module.js'; 導(dǎo)出:
export const functionName = () => {}; CommonJS 使用 require 和 module.exports 語法來導(dǎo)入和導(dǎo)出模塊。
導(dǎo)入:
const { functionName } = require('./module'); 導(dǎo)出:
module.exports.functionName = () => {}; 2. 靜態(tài) vs 動態(tài)加載
ESM 是靜態(tài)的,支持 編譯時優(yōu)化,如 Tree Shaking。
CommonJS 是動態(tài)的,模塊加載是 運行時執(zhí)行,更靈活,但沒有靜態(tài)優(yōu)化能力。
ESModule(ESM):
靜態(tài)分析:
ESM是靜態(tài)的,意味著在編譯時,瀏覽器或構(gòu)建工具就能夠分析出所有的依賴關(guān)系。這樣可以進(jìn)行優(yōu)化(如 Tree Shaking)來刪除未使用的代碼。import和export語句必須出現(xiàn)在模塊的頂部,不能在條件語句或函數(shù)中使用。why?
??因為 ES Modules(ESM)的設(shè)計是「靜態(tài)的」,不是「動態(tài)的」。import和 export必須在模塊的頂層(即模塊代碼的最外層作用域)被靜態(tài)分析,這樣 JavaScript 引擎 / 打包工具 才能在不運行代碼的情況下,確定模塊之間的依賴關(guān)系,進(jìn)行優(yōu)化、打包、Tree-Shaking 等操作。??
??如果你把 import 放到 if 語句、函數(shù)、循環(huán)等內(nèi)部,那么:??
引擎或打包工具就 ??無法在代碼運行前確定這個模塊依賴了誰??,因為是否導(dǎo)入取決于運行時的條件,這就違反了“靜態(tài)模塊”的原則。

CommonJS:
動態(tài)加載:
CommonJS是動態(tài)的,模塊是在運行時加載的,這意味著require()調(diào)用可以出現(xiàn)在任何地方(例如,在函數(shù)或條件語句中)。這為代碼的靈活性提供了更多的選擇。require()調(diào)用是在執(zhí)行時解析的,因此不能像import一樣進(jìn)行靜態(tài)優(yōu)化。
3. 加載機(jī)制
ESM 支持 異步加載,適用于現(xiàn)代的瀏覽器和服務(wù)器端。
CommonJS 采用 同步加載,適用于 Node.js 環(huán)境,通常是基于文件系統(tǒng)的加載方式。
ESModule:模塊是 異步加載 的,在瀏覽器中,
ESM可以通過網(wǎng)絡(luò)請求異步加載模塊(通過<script type="module">),而在 Node.js 中,ESM模塊也可以通過import異步加載。瀏覽器:
<script type="module" src="module.js">Node.js:使用
import語句加載模塊。
CommonJS:模塊是 同步加載 的。
require()是在模塊執(zhí)行時同步加載模塊的,這意味著當(dāng)一個模塊被加載時,程序會等待該模塊加載完成后繼續(xù)執(zhí)行。這種方式適合于服務(wù)端的應(yīng)用,如 Node.js。
4. 支持的環(huán)境
ESM 是 現(xiàn)代的標(biāo)準(zhǔn)模塊化,已被瀏覽器和 Node.js 逐漸支持。
CommonJS 主要用于 Node.js 環(huán)境。
ESModule(ESM):
在現(xiàn)代瀏覽器中,
ESM已經(jīng)得到了廣泛支持,可以直接通過<script type="module">標(biāo)簽在 HTML 頁面中使用。在 Node.js 中,從
v12版本開始也逐漸支持ESM,但是需要使用.mjs擴(kuò)展名或在package.json文件中設(shè)置"type": "module"。
CommonJS:
主要用于 Node.js 環(huán)境中,它在瀏覽器端原生不被支持,需要通過工具(如 Webpack、Browserify)進(jìn)行打包。
5. 模塊的導(dǎo)出方式
ESM 支持 命名導(dǎo)出 和 默認(rèn)導(dǎo)出。
CommonJS 使用
module.exports導(dǎo)出模塊,但只能導(dǎo)出一個對象。
ESModule:
export 可以導(dǎo)出多個變量、函數(shù)、類等。
export const name = 'John';
export function greet() { console.log('Hello'); }default 導(dǎo)出:每個模塊可以有一個默認(rèn)導(dǎo)出,可以通過 export default 來指定。
export default function() { console.log('Hello Default'); } 導(dǎo)入:默認(rèn)導(dǎo)入可以用任意名稱來接收導(dǎo)出的默認(rèn)值。
import func from './module'; // 導(dǎo)入默認(rèn)導(dǎo)出
CommonJS:
module.exports 用來導(dǎo)出模塊。
module.exports.name = 'John';
module.exports.greet = function() { console.log('Hello'); };只能導(dǎo)出一個對象或函數(shù)。
導(dǎo)入:require 導(dǎo)入整個模塊。
const myModule = require('./module');
myModule.greet();6. 循環(huán)依賴
ESM 和 CommonJS 都能處理循環(huán)依賴,但 ESM 由于是靜態(tài)解析,能更好地避免此類問題,并且避免重復(fù)加載模塊。
ESModule(ESM):
ESM 支持 靜態(tài)解析,即使在模塊之間存在循環(huán)依賴,瀏覽器和構(gòu)建工具也能正確處理。在循環(huán)依賴的情況下,ESM 會返回 模塊的已加載版本,而不會重復(fù)加載模塊。
CommonJS:
CommonJS 也能處理循環(huán)依賴,但它是 在運行時解析 的,可能會返回部分加載的模塊內(nèi)容,而不是完全加載的模塊。
7. 支持的功能:動態(tài)導(dǎo)入
ESM 支持 動態(tài)導(dǎo)入,可以按需加載模塊。
CommonJS 只有 同步加載 模塊。
ESModule:ESM 支持 動態(tài)導(dǎo)入,可以通過
import()函數(shù)動態(tài)加載模塊。這使得開發(fā)者能夠按需加載代碼,增強性能。import('./module').then(module => { // 使用 module });CommonJS:CommonJS 沒有原生支持動態(tài)導(dǎo)入,它的
require是同步的。
總結(jié)對比:
| 特性 | ESModule (ESM) | CommonJS |
|---|---|---|
| 導(dǎo)入導(dǎo)出語法 | import { x } from 'module' / export | const x = require('module') / module.exports |
| 模塊化方式 | 靜態(tài)模塊化,支持樹搖(Tree Shaking) | 動態(tài)模塊化,按需加載 |
| 加載方式 | 異步加載,適用于瀏覽器和 Node.js | 同步加載,主要用于 Node.js |
| 兼容性 | 支持現(xiàn)代瀏覽器和 Node.js(通過 .mjs 或 "type": "module") | 主要用于 Node.js |
| 默認(rèn)導(dǎo)出 | export default | module.exports = |
| 支持動態(tài)導(dǎo)入 | import() 動態(tài)導(dǎo)入 | 不支持動態(tài)導(dǎo)入 |
| 循環(huán)依賴 | 靜態(tài)解析,避免重復(fù)加載 | 在運行時處理循環(huán)依賴,返回部分加載模塊 |
使用場景:
ESModules 是現(xiàn)代的標(biāo)準(zhǔn)模塊化方案,推薦用于前端開發(fā)以及支持
ESM的 Node.js 環(huán)境。CommonJS 主要用于 Node.js 環(huán)境,尤其適合傳統(tǒng)的服務(wù)器端模塊。
當(dāng)瀏覽器不支持ES Modules時
解決方法:使用 script 標(biāo)簽的 type="module" 和回退方案
1. 使用<script>標(biāo)簽的nomodule屬性
HTML5 引入了 nomodule 屬性,這個屬性可以用來為不支持模塊的瀏覽器提供備用腳本。
原理:
<script type="module">會在支持ES Modules的瀏覽器中加載,而nomodule會在不支持ES Modules的瀏覽器中加載。因此,可以通過這種方式為不支持ES Modules的瀏覽器提供傳統(tǒng)的、非模塊化的 JavaScript。
示例代碼:
<!-- 模塊化腳本,在支持 ES Module 的瀏覽器中執(zhí)行 --> <script type="module" src="main.mjs"></script> <!-- 非模塊化腳本,僅在不支持模塊的瀏覽器中執(zhí)行 --> <script nomodule src="main-legacy.js"></script>
type="module":瀏覽器支持ES Modules時,會加載main.mjs腳本。nomodule:僅當(dāng)瀏覽器不支持模塊時,會加載main-legacy.js腳本。這樣,老舊瀏覽器會執(zhí)行傳統(tǒng)的非模塊化腳本。
2. 使用 JavaScript 編譯工具(如 Babel)將代碼轉(zhuǎn)譯為 ES5
如果要支持不支持 ES Modules 的舊版瀏覽器(如 IE 11 或一些早期版本的 Edge),還需要使用工具將 JavaScript 代碼轉(zhuǎn)譯為兼容的版本。
Babel:Babel 是一個非常流行的 JavaScript 編譯器,它可以將現(xiàn)代 JavaScript 代碼(包括
ES Modules)轉(zhuǎn)譯為兼容更廣泛瀏覽器的代碼。Webpack 或 Rollup:這些打包工具也可以與 Babel 配合使用,將
ES Modules轉(zhuǎn)換為傳統(tǒng)的 CommonJS 或 IIFE 模式,從而確保兼容舊瀏覽器。
配置 Babel 轉(zhuǎn)譯ES Modules:
安裝 Babel 和相關(guān)插件:
如果你還沒有 Babel 環(huán)境,可以通過以下命令安裝 Babel 和必要的插件:npm install --save-dev @babel/core @babel/preset-env babel-loader
Babel 配置文件(babel.config.json):
在
babel.config.json中,配置 Babel 轉(zhuǎn)譯ES Modules為 CommonJS 或其他兼容格式:{ "presets": [ [ "@babel/preset-env", { "modules": "commonjs" } ] ] }"modules": "commonjs":這將ES Modules轉(zhuǎn)換為CommonJS,以確??梢栽诓恢С?nbsp;ES Modules的瀏覽器中運行。
Webpack 配置(可選):
如果使用 Webpack,你可以配置 Webpack 來確保舊瀏覽器能夠處理編譯后的 JavaScript:
// webpack.config.js module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: __dirname + '/dist' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } };最終生成的代碼:
Babel 會將現(xiàn)代 JavaScript(如
import/export)轉(zhuǎn)譯為兼容 ES5 的代碼,這樣即使在舊瀏覽器中,也能正常加載并執(zhí)行。
3. 使用 Polyfill
如果你的 JavaScript 中使用了其他新的 JavaScript 特性(例如 Promise、fetch 等),而這些特性在舊瀏覽器中沒有實現(xiàn),可以使用 polyfill 來提供對這些特性的支持。
Polyfill:Polyfill 是一個 JavaScript 庫,用于提供對新特性的支持。例如,
core-js是一個流行的 polyfill 庫,可以為不支持的瀏覽器提供ES6、ES7等特性的實現(xiàn)。
如何使用 polyfill:
安裝 core-js:
npm install core-js
在 JavaScript 中引入 polyfill:
import 'core-js/stable'; import 'regenerator-runtime/runtime'; // 如果使用了 async/await
這會為不支持的瀏覽器提供必要的功能實現(xiàn)。
總結(jié):
如果你需要在不支持 ES Modules 的瀏覽器中運行代碼,可以使用以下幾種方法:
nomodule 和 type="module":為支持
ES Modules的瀏覽器加載模塊,為不支持的瀏覽器加載傳統(tǒng)腳本。使用 Babel:通過 Babel 將
ES Modules轉(zhuǎn)換為兼容舊瀏覽器的代碼。Polyfill:使用 polyfill 庫來填補舊瀏覽器缺少的功能,確?,F(xiàn)代 JavaScript 特性在舊瀏覽器中能夠正常運行。

到此這篇關(guān)于JS模塊化開發(fā)之EsModule和Common.js區(qū)別的文章就介紹到這了,更多相關(guān)JS EsModule和Common.js區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript針對網(wǎng)頁節(jié)點的增刪改查用法實例
這篇文章主要介紹了JavaScript針對網(wǎng)頁節(jié)點的增刪改查用法,實例分析了JavaScript操作網(wǎng)頁節(jié)點的技巧,非常具有實用價值,需要的朋友可以參考下2015-02-02
讓bootstrap的carousel支持滑動滾屏的實現(xiàn)代碼
這篇文章主要介紹了讓bootstrap的carousel支持滑動滾屏的實現(xiàn)代碼,需要的朋友可以參考下2017-11-11
基于JS實現(xiàn)彈出一個隱藏的div窗口body頁面變成灰色并且不可被編輯
這篇文章主要介紹了基于JS實現(xiàn)彈出一個隱藏的div窗口body頁面變成灰色并且不可被編輯的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12
一文詳解如何通過JavaScript動態(tài)修改元素的樣式
這篇文章主要介紹了如何通過JavaScript動態(tài)修改元素的樣式,三種方式分別是直接操作元素的style屬性、通過classList屬性添加或移除類名、以及使用CSSStyleDeclaration對象的setProperty方法,每種方法都有其適用場景,需要的朋友可以參考下2024-12-12

