ES6模块与CommonJS对比解析
2026-02-14 17:00:46
0浏览
收藏
ES6模块与CommonJS虽同为JavaScript模块化方案,却在解析时机、语法约束、导出机制和运行环境支持上存在根本差异:ES6模块静态解析、强制顶层import/export、支持Tree-shaking且默认导出为绑定引用;而CommonJS动态执行、require可灵活嵌套但无法被构建工具优化,其module.exports本质是对象赋值。二者互操作时易因default包装、导入方式错配导致静默错误,尤其在Node.js中还需严格区分.mjs后缀或package.json的"type": "module"配置,否则跨类型加载会直接失败——理解这些差异,是避免构建报错、提升代码可维护性与性能优化效果的关键。

ES6 模块(import/export)是静态解析的
浏览器和现代打包工具(如 Webpack、Vite)在构建阶段就确定模块依赖关系,不允许动态决定 import 路径或条件加载(除非用 import() 动态导入)。这意味着:
if (condition) {
import { foo } from './module.js'; // ❌ 语法错误:不能出现在 if 内
}而
import 必须写在顶层作用域。这种静态性让 Tree-shaking 成为可能,也便于 IDE 提前校验导出名是否存在。
CommonJS(require/module.exports)是运行时执行的
require 是函数调用,可以出现在任意位置,支持拼接路径、条件引入、甚至循环依赖(虽然不推荐):
const path = './' + env + '/config.js';
const config = require(path); // ✅ 合法(Node.js 环境下)
但这也意味着无法在构建期分析依赖,Tree-shaking 效果差;且 Node.js 中默认以 CommonJS 方式加载
.js 文件(除非
type: "module" 显式声明)。
默认导出行为不同,混用时容易出错
ES6 的 export default 导出的是一个值的**绑定引用**,而 CommonJS 的 module.exports 是一个对象的**属性赋值**:
export default { a: 1 } → 导出的是该对象本身,修改其属性会影响所有导入者module.exports = { a: 1 } → 导入后得到的是该对象的拷贝(浅拷贝),后续 module.exports = ... 赋值会完全替换它
更关键的是互操作陷阱:
// commonjs.js
module.exports = { count: 0 };
// es6.js
import obj from './commonjs.js'; // ❌ 实际得到的是 { default: { count: 0 } }
// 正确写法(兼容 CommonJS 输出):
import * as obj from './commonjs.js'; // obj.default 才是原对象
// 或用 require:
const obj = require('./commonjs.js');Node.js 中两者共存需注意文件后缀与配置
Node.js v12+ 支持 ES6 模块,但有硬性约束:
.mjs 文件强制按 ES 模块解析.js 文件默认按 CommonJS 解析,除非所在 package.json 中设置了 "type": "module"require() 不能直接加载 .mjs(会报错),import 也不能加载未声明 type: module 的 .js
跨类型调用必须通过
createRequire 或
dynamic import() 绕过限制,不是“写了就能用”。
实际项目中,如果用 Vite 或 Webpack,它们会自动处理差异;但在纯 Node 环境跑脚本时,模块类型不匹配是最常卡住的地方。
到这里,我们也就讲完了《ES6模块与CommonJS对比解析》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!
- 下一篇
- 一两等于多少克?市制换算技巧详解