ES6 模块(ESM)和 CommonJS 是 JavaScript 中两种主要的模块规范,它们在设计理念、语法和行为上有显著区别。以下是两者的核心差异:
1. 语法规范与用途
•
ES6 模块(ESM)
是 ECMAScript 2015 标准化的模块系统,适用于浏览器和 Node.js(需显式启用),是 JavaScript 官方模块规范。
核心关键字:export
、import
、export default
。•
CommonJS
是 Node.js 原生的模块规范,主要为服务器端设计,早期用于解决 Node.js 中的模块依赖问题。
核心关键字:module.exports
、exports
、require()
。
2. 导出 / 导入语法
操作 |
ES6 模块(ESM) |
CommonJS |
---|---|---|
默认导出 |
|
|
命名导出 |
|
|
导入默认 |
|
|
导入命名 |
|
|
3. 加载时机与方式
•
ES6 模块:静态加载
•
导入和导出语句在代码解析阶段执行(编译时加载),而非运行时。
•
导入路径必须是静态字符串(不能动态拼接)。
•
支持
import()
动态导入(返回 Promise)。
示例:
javascript
运行
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown// 静态导入(解析时执行) import { utils } from './tools.js'; // 动态导入(运行时执行) import('./tools.js').then(module => { ... });
•
CommonJS:动态加载
•
导入(
require()
)在代码运行阶段执行,支持动态路径。•
模块加载是同步的(Node.js 中对本地模块有缓存优化)。
示例:
javascript
运行
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown// 支持动态路径 const path = './tools.js'; const utils = require(path);
4. 模块输出的本质
•
ES6 模块:值的引用
•
导出的是值的只读引用,模块内部值变化时,导入方会同步更新。
•
导入的变量是只读的(不能重新赋值)。
示例:
javascript
运行
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown// module.js export let count = 0; export function increment() { count++; } // main.js import { count, increment } from './module.js'; increment(); console.log(count); // 输出 1(跟随模块内部变化)
•
CommonJS:值的拷贝
•
导出的是值的拷贝(对象导出的是引用地址的拷贝),模块内部值变化不影响导入方。
•
导入的变量可以重新赋值。
示例:
javascript
运行
--javascripttypescriptshellbashsqljsonhtmlcssccppjavarubypythongorustmarkdown// module.js let count = 0; module.exports = { count, increment: () => { count++; } }; // main.js const { count, increment } = require('./module.js'); increment(); console.log(count); // 输出 0(拷贝的值未更新)
5. 循环依赖处理
•
ES6 模块
由于静态解析,模块在加载时会先创建「模块记录」,循环依赖时能正确引用未完全初始化的模块(返回部分导出值)。•
CommonJS
循环依赖时,会返回模块当前已执行部分的导出值(可能是不完整的),依赖后续执行补充。
6. 顶层 this
指向
•
ES6 模块:顶层
this
为undefined
。•
CommonJS:顶层
this
指向当前模块的module.exports
。
7. 使用场景
•
ES6 模块
•
浏览器环境(原生支持,需在
<script type="module">
中使用)。•
现代前端工程(Vue、React 项目,通过 Webpack/Vite 打包)。
•
Node.js 13.2+(需在
package.json
中设置"type": "module"
)。
•
CommonJS
•
Node.js 环境(默认模块系统)。
•
早期 Node.js 生态的库(如 Express 中间件)。
总结
特性 |
ES6 模块(ESM) |
CommonJS |
---|---|---|
加载时机 |
解析时(静态) |
运行时(动态) |
输出本质 |
值的引用(只读) |
值的拷贝(可修改) |
循环依赖处理 |
基于模块记录(更可靠) |
基于执行状态(可能不完整) |
适用环境 |
浏览器 + 现代 Node.js |
Node.js 原生 |
动态导入支持 |
|
|
现代前端开发以 ES6 模块为主,而 CommonJS 主要用于 Node.js 后端开发。在实际项目中,两者可通过打包工具(如 Webpack)相互兼容。