javascript模块化如何实现_ES6模块与CommonJS有何区别【教程】

11次阅读

es6模块与Commonjs本质不同:前者静态、编译期确定依赖,后者动态、运行时加载;混用会导致ReferenceError、undefined导出等问题,需依场景选择并正确配置。

javascript模块化如何实现_ES6模块与CommonJS有何区别【教程】

ES6 模块(import/export)和 CommonJS(require/module.exports)不是“换种写法就行”的关系——它们在加载时机、导出行为、循环引用处理、运行时表现上根本不同。直接混用或盲目替换会触发 ReferenceErrorundefined 导出、甚至打包器报错。

ES6 模块是静态的,CommonJS 是动态的

这是最核心差异。ES6 的 import 必须在模块顶层,不能放在 if 或函数里;而 require 可以随时调用,支持条件加载、拼接路径等运行时逻辑。

常见错误现象:

  • import 写在 if 块里 → 语法错误:Cannot use import statement outside a module
  • import { foo } from './utils.js'utils.js 实际是 CommonJS 格式(无 export)→ node.jsCannot access 'foo' before initialization 或导入为 undefined

实操建议:

立即学习Java免费学习笔记(深入)”;

  • node.js 中启用 ES6 模块需在 package.json"type": "module",否则默认按 CommonJS 解析
  • 若想在 CommonJS 文件中导入 ES6 模块,必须用 await import('./es-module.js')(动态导入),不能用 require
  • webpack/vite 等工具能自动处理互转,但底层仍依赖静态分析 —— 所以 export 不能写在条件分支里

export defaultmodule.exports 不是一对一映射

ES6 的 export default 导出的是一个值的**绑定**(binding),CommonJS 的 module.exports 是一个可随意赋值的对象引用。这意味着:

  • ES6 中修改 export default 对应的变量,其他模块看到的值会实时更新(如计数器、状态对象)
  • CommonJS 中一旦执行 module.exports = xxx,后续再改 xxx 不会影响已导出的值

示例对比:

// esm.js let count = 0; export default () => ++count;  // cjs.js let count = 0; module.exports = () => ++count;

如果两个文件都被多次 import / require,ES6 版本共享同一份 count;CommonJS 版本每次 require 都新建闭包count 各自独立。

循环引用时,ES6 返回未初始化的绑定,CommonJS 返回已执行的 exports 对象

这是最容易踩坑的场景。比如 A 导入 B,B 又导入 A:

  • CommonJS:A 执行到 require('./b') 时,B 已导出空 exports 对象,A 拿到它继续执行;B 后续给 exports.xxx 赋值,A 能读到
  • ES6:A 的 import { x } from './b' 在解析阶段就建立绑定,但此时 B 还没执行完,xundefined;即使 B 后面 export const x = 1,A 中的 x 仍为 undefined(除非用 export default 或命名导出后立即赋值)

实操建议:

立即学习Java免费学习笔记(深入)”;

  • 避免循环引用 —— 提取公共逻辑到第三个模块
  • 若必须循环,ES6 下优先用 export default(它不依赖命名绑定顺序),或确保导出语句在模块顶部且无依赖
  • Node.js 的 require 缓存机制会让循环引用“看起来工作”,但这不是可靠设计依据

浏览器中只能用 ES6 模块,Node.js 默认只认 CommonJS

浏览器原生只支持 type="module",不理解 require;Node.js v12+ 支持 ES6 模块,但需显式声明(.mjs 后缀或 "type": "module"),否则一律当 CommonJS 处理。

常见错误现象:

  • html 中写 ,但 index.js 用了 import → 控制台报 Uncaught SyntaxError: Cannot use import statement outside a module
  • Node.js 中 index.jsimport 却没设 "type": "module"SyntaxError: Cannot use import statement outside a module

实操建议:

立即学习Java免费学习笔记(深入)”;

  • 浏览器端:用 ,路径必须是相对/绝对 URL(不能省略 .js
  • Node.js:要么统一用 .mjs 后缀,要么在 package.json 顶层加 "type": "module";混合项目可用 createRequire 兼容旧代码
  • 跨环境库(如工具函数包)建议同时提供 ESM 和 CJS 构建产物,并在 package.json 中用 "exports" 字段精确控制入口

真正难的不是语法转换,而是理解两种模块系统背后的设计哲学:一个是编译期确定依赖图、强调不可变绑定与静态分析;另一个是运行时灵活加载、强调可变状态与动态能力。很多“兼容问题”其实源于强行把一种范式套进另一种约束里。

text=ZqhQzanResources