JavaScript中ESModule和Commonjs模塊的區(qū)別
ES Module(ESM)和 CommonJS(CJS)是 JavaScript 中兩種主流的模塊化規(guī)范。ESM 是 ES6 推出的官方標(biāo)準(zhǔn),而 CommonJS 則是 Node.js 早期采用的模塊化方案。
以下從幾個(gè)核心角度為你詳細(xì)拆解:
1. 核心差異速覽表
| 對比角度 | CommonJS (CJS) | ES Module (ESM) |
|---|---|---|
| 基本語法 | require() 導(dǎo)入,module.exports 導(dǎo)出 | import 導(dǎo)入,export 導(dǎo)出 |
| 加載時(shí)機(jī) | 運(yùn)行時(shí)加載(動(dòng)態(tài)) | 編譯時(shí)加載(靜態(tài)) |
| 加載方式 | 同步加載 | 異步加載(瀏覽器端) |
| 導(dǎo)出本質(zhì) | 值的拷貝(淺拷貝) | 值的引用(Live Binding) |
| 代碼優(yōu)化 | 不支持 Tree Shaking | 支持 Tree Shaking |
| 頂層 this | 指向 module.exports | undefined(嚴(yán)格模式) |
2. 深度解析各個(gè)角度
語法與規(guī)范來源
- CommonJS:是社區(qū)提出的規(guī)范,主要用于 Node.js 服務(wù)端環(huán)境。它的語法非常直觀,使用
require()來引入模塊,使用module.exports或exports來向外暴露功能。 - ES Module:是 ECMAScript 2015 (ES6) 的官方語言標(biāo)準(zhǔn),旨在統(tǒng)一瀏覽器和服務(wù)端的模塊化。它使用
import和export關(guān)鍵字,語法更加語義化,支持命名導(dǎo)出和默認(rèn)導(dǎo)出。
加載時(shí)機(jī)與方式(最核心的區(qū)別)
- CommonJS 是“運(yùn)行時(shí)同步加載”:當(dāng)你代碼執(zhí)行到
require()這一行時(shí),才會(huì)去加載并執(zhí)行對應(yīng)的模塊文件。這種方式在服務(wù)端(讀取本地硬盤文件)非常高效,但在瀏覽器端會(huì)因?yàn)榫W(wǎng)絡(luò)請求阻塞頁面渲染,所以瀏覽器不原生支持。 - ES Module 是“編譯時(shí)靜態(tài)加載”:JS 引擎在解析代碼的階段(編譯時(shí)),就會(huì)通過分析
import和export語句,提前確定好模塊之間的依賴關(guān)系。在瀏覽器中,ESM 默認(rèn)是異步加載的,不會(huì)阻塞 HTML 的解析。
導(dǎo)出的本質(zhì):值拷貝 vs 值的引用 這是兩者在實(shí)際開發(fā)中最容易產(chǎn)生 Bug 的差異點(diǎn):
- CommonJS(值拷貝):導(dǎo)出的是模塊內(nèi)部變量的一個(gè)副本。如果模塊內(nèi)部修改了這個(gè)變量,外部引入的地方是感知不到的。
// CommonJS 示例 // counter.js let count = 0; module.exports = { count }; setTimeout(() => { count = 1; }, 1000); // 內(nèi)部修改 // main.js const { count } = require('./counter.js'); console.log(count); // 0 setTimeout(() => { console.log(count); }, 1100); // 依然是 0,因?yàn)槭强截惖呐f值 - ES Module(值的引用 / Live Binding):導(dǎo)出的是對模塊內(nèi)部變量的動(dòng)態(tài)引用。當(dāng)模塊內(nèi)部修改了變量,所有引入該變量的地方都會(huì)同步更新。
// ESM 示例 // counter.js export let count = 0; setTimeout(() => { count = 1; }, 1000); // 內(nèi)部修改 // main.js import { count } from './counter.js'; console.log(count); // 0 setTimeout(() => { console.log(count); }, 1100); // 1,實(shí)時(shí)同步了最新值
代碼優(yōu)化(Tree Shaking)
- ES Module:由于它是靜態(tài)的,打包工具(如 Webpack、Rollup、Vite)可以在打包階段就分析出哪些代碼被使用了,哪些沒有。未被使用的代碼(Dead Code)會(huì)被直接剔除,這個(gè)過程叫 Tree Shaking(搖樹優(yōu)化),能顯著減小打包體積。
- CommonJS:由于
require()可以在代碼運(yùn)行時(shí)動(dòng)態(tài)執(zhí)行(比如寫在if判斷里),打包工具很難在編譯階段確定到底引用了哪些模塊,因此無法有效支持 Tree Shaking。
運(yùn)行環(huán)境與兼容性
- CommonJS:Node.js 的默認(rèn)模塊規(guī)范,生態(tài)極其成熟。在瀏覽器中無法直接使用,必須通過 Webpack、Browserify 等工具打包轉(zhuǎn)換。
- ES Module:現(xiàn)代瀏覽器原生支持(通過
<script type="module">),也是現(xiàn)代前端框架(Vue3, React)和構(gòu)建工具(Vite)的首選。Node.js 從 v12 版本后也開始支持 ESM,但需要在package.json中配置"type": "module"或使用.mjs后綴。
總結(jié)建議: 在現(xiàn)代前端開發(fā)和新的 Node.js 項(xiàng)目中,優(yōu)先推薦使用 ES Module,因?yàn)樗鼧?biāo)準(zhǔn)、性能更好且支持代碼優(yōu)化。但在維護(hù)一些老舊的 Node.js 項(xiàng)目或依賴某些僅支持 CJS 的第三方庫時(shí),你依然會(huì)頻繁接觸到 CommonJS。
到此這篇關(guān)于JavaScript中ESModule和Commonjs模塊的區(qū)別的文章就介紹到這了,更多相關(guān)ESModule和Commonjs區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
通過JS自動(dòng)隱藏手機(jī)瀏覽器的地址欄實(shí)現(xiàn)原理與代碼
大家通過手機(jī)自帶瀏覽器打開百度、淘寶,在首頁加載完畢后,會(huì)自動(dòng)隱藏頁面上方的地址欄,感興趣的朋友可以參考下2013-01-01
javascript實(shí)現(xiàn)的DES加密示例
DES加密算法的方法把用戶信息在發(fā)送的時(shí)候進(jìn)行加密很實(shí)用,下面有個(gè)不錯(cuò)的示例,需要的朋友可以參考下2013-10-10
js編寫當(dāng)天簡單日歷效果【實(shí)現(xiàn)代碼】
下面小編就為大家?guī)硪黄猨s編寫當(dāng)天簡單日歷效果【實(shí)現(xiàn)代碼】。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考2016-05-05
JavaScript對Cookie進(jìn)行讀寫操作實(shí)例
這篇文章主要介紹了JavaScript對Cookie進(jìn)行讀寫操作的方法,實(shí)例分析了javascript針對cookie的讀寫操作技巧,非常簡單實(shí)用,需要的朋友可以參考下2015-07-07

