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

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

到此這篇關(guān)于JS模塊化開(kāi)發(fā)之EsModule和Common.js區(qū)別的文章就介紹到這了,更多相關(guān)JS EsModule和Common.js區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript針對(duì)網(wǎng)頁(yè)節(jié)點(diǎn)的增刪改查用法實(shí)例
這篇文章主要介紹了JavaScript針對(duì)網(wǎng)頁(yè)節(jié)點(diǎn)的增刪改查用法,實(shí)例分析了JavaScript操作網(wǎng)頁(yè)節(jié)點(diǎn)的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02
原生javascript實(shí)現(xiàn)勻速運(yùn)動(dòng)動(dòng)畫(huà)效果
這篇文章主要為大家詳細(xì)介紹了原生javascript實(shí)現(xiàn)勻速運(yùn)動(dòng)動(dòng)畫(huà)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02
讓bootstrap的carousel支持滑動(dòng)滾屏的實(shí)現(xiàn)代碼
這篇文章主要介紹了讓bootstrap的carousel支持滑動(dòng)滾屏的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-11-11
javascript+Canvas實(shí)現(xiàn)畫(huà)板功能
這篇文章主要為大家詳細(xì)介紹了javascript+Canvas實(shí)現(xiàn)畫(huà)板功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
基于JS實(shí)現(xiàn)彈出一個(gè)隱藏的div窗口body頁(yè)面變成灰色并且不可被編輯
這篇文章主要介紹了基于JS實(shí)現(xiàn)彈出一個(gè)隱藏的div窗口body頁(yè)面變成灰色并且不可被編輯的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-12-12
JS實(shí)現(xiàn)的網(wǎng)頁(yè)背景閃電閃爍效果代碼
這篇文章主要介紹了JS實(shí)現(xiàn)的網(wǎng)頁(yè)背景閃電閃爍效果代碼,涉及JavaScript定時(shí)函數(shù)結(jié)合頁(yè)面元素樣式操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
一文詳解如何通過(guò)JavaScript動(dòng)態(tài)修改元素的樣式
這篇文章主要介紹了如何通過(guò)JavaScript動(dòng)態(tài)修改元素的樣式,三種方式分別是直接操作元素的style屬性、通過(guò)classList屬性添加或移除類(lèi)名、以及使用CSSStyleDeclaration對(duì)象的setProperty方法,每種方法都有其適用場(chǎng)景,需要的朋友可以參考下2024-12-12

