commonjs 和 esm 的区别
CommonJS 和 ESM(ES Modules)是 JavaScript 中最常用的两种模块规范,二者有明显的区别:
一、定义上的区别
规范 | 描述 | 使用场景 |
---|---|---|
CommonJS | Node.js 最初设计的模块标准 | Node.js 环境 |
ESM(ES Modules) | ECMAScript 官方的模块标准 | 浏览器、现代 Node.js |
二、语法区别
CommonJS:
- 使用
require
引入模块。 - 使用
module.exports
或exports
导出内容。
js
// 导入模块
const lodash = require("lodash");
// 导出模块
module.exports = {
add(a, b) {
return a + b;
},
};
ES Modules:
- 使用
import
引入模块。 - 使用
export
或export default
导出内容。
js
// 导入模块
import lodash from "lodash";
// 导出模块
export const add = (a, b) => a + b;
// 默认导出
export default function multiply(a, b) {
return a * b;
}
三、加载时机的差别
特性 | CommonJS | ESM |
---|---|---|
加载时机 | 运行时(同步) | 编译时(静态分析) |
加载机制 | 模块整体加载 | 支持按需加载,动态 import |
CommonJS 模块是运行时加载:
- 每次导入模块都会执行完整模块代码,导出对象的拷贝。
ES Modules 模块是静态加载:
- 编译时就确定依赖关系,可进行 tree-shaking 优化。
- 支持动态导入(
import()
)。
四、模块缓存方式
特性 | CommonJS | ESM |
---|---|---|
缓存 | ✅ 首次加载后缓存 | ✅ 模块实例化后缓存 |
CommonJS:
- 首次加载后,会缓存模块结果,多次引用同一模块返回同一个实例。
ES Modules:
- 同样具有缓存机制,但静态分析可进一步优化,避免未使用代码加载。
五、值传递方式
特性 | CommonJS | ESM |
---|---|---|
传递方式 | 值的拷贝 | 绑定引用(live bindings) |
- CommonJS 导出的是值的副本,修改原模块导出变量,不会影响导入方:
js
// CommonJS 导出模块
let count = 0;
module.exports = { count };
// 导入
const mod = require("./mod.js");
mod.count = 5; // 不影响原模块的值
- ES Modules 导出的是引用绑定(实时绑定):
js
// ESM 导出模块
export let count = 0;
export function increment() {
count++;
}
// 导入
import { count, increment } from "./mod.js";
increment();
console.log(count); // 实时更新
六、浏览器与 Node.js 支持程度
环境 | CommonJS | ESM |
---|---|---|
浏览器 | ❌ 原生不支持 | ✅ 原生支持 |
Node.js(旧版) | ✅ 原生支持 | ❌ 需额外配置 |
Node.js(新版) | ✅ 支持(默认) | ✅ 支持(需.mjs 或 type=module) |
- 浏览器原生只支持 ESM,CommonJS 需打包工具(如 Webpack)。
- Node.js 新版同时支持,但 ESM 需额外标记或后缀(
.mjs
或package.json
中type: "module"
)。
七、使用场景对比总结
特性 | CommonJS | ESM (ES Modules) |
---|---|---|
使用场景 | Node.js(服务器端) | 浏览器、现代 JavaScript 开发 |
性能优化 | 较差,不能 Tree-Shaking | 更好,支持 Tree-Shaking |
加载机制 | 运行时加载,动态同步加载 | 编译时加载,支持动态异步加载 |
生态支持 | 成熟、广泛 | 逐渐成为主流,支持逐渐完善 |
八、实战应用建议:
前端项目:推荐 ESM,更加现代化,支持浏览器原生,构建优化能力强。
Node.js 项目:
- 旧项目和生态库广泛使用 CommonJS。
- 新项目推荐逐步迁移到 ESM,以利用更好的性能优化与开发体验。
🔖 总结表格
区别点 | CommonJS | ES Modules (ESM) |
---|---|---|
模块规范 | Node.js 标准 | ECMAScript 官方标准 |
加载方式 | 运行时加载 | 编译时静态加载 |
导出导入语法 | require/module.exports | import/export |
值传递 | 值拷贝 | 引用绑定(live bindings) |
Tree-Shaking 支持 | ❌ | ✅ |
浏览器支持 | 需打包工具 | 原生支持 |
动态导入 | 不支持(同步加载) | 支持(import()) |
以上明确了 CommonJS 与 ESM 在使用方式、性能和环境上的差异,这类问题通常作为前端开发或 Node.js 开发的重要基础面试题。