ES6和CommonJS模块区别

ES6 模块(ESM)和 CommonJS 是 JavaScript 中两种主要的模块规范,它们在设计理念、语法和行为上有显著区别。以下是两者的核心差异:

1. 语法规范与用途

  • ES6 模块(ESM)

    是 ECMAScript 2015 标准化的模块系统,适用于浏览器和 Node.js(需显式启用),是 JavaScript 官方模块规范。

    核心关键字:exportimportexport default

  • CommonJS

    是 Node.js 原生的模块规范,主要为服务器端设计,早期用于解决 Node.js 中的模块依赖问题。

    核心关键字:module.exportsexportsrequire()

2. 导出 / 导入语法

操作 ES6 模块(ESM) CommonJS
默认导出 export default { ... } module.exports = { ... }
命名导出 export const a = 1; export function f() {} exports.a = 1; exports.f = function() {}
导入默认 import obj from './module.js' const obj = require('./module.js')
导入命名 import { a, f } from './module.js' const { a, f } = require('./module.js')

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 模块:顶层 thisundefined

  • 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 原生
动态导入支持 import()(返回 Promise) require() 天然支持

现代前端开发以 ES6 模块为主,而 CommonJS 主要用于 Node.js 后端开发。在实际项目中,两者可通过打包工具(如 Webpack)相互兼容。

相关推荐
代码搬运媛1 小时前
Jest 测试框架详解与实现指南
前端
counterxing2 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq2 小时前
windows下nginx的安装
linux·服务器·前端
之歆2 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜2 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai108083 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
kyriewen4 小时前
产品经理把PRD写成“天书”,我用AI半小时重写了一遍,他当场愣住
前端·ai编程·cursor
humcomm5 小时前
元框架的工作原理详解
前端·前端框架
canonical_entropy5 小时前
Attractor Before Harness: AI 大规模开发的方法论
前端·aigc·ai编程
zhangxingchao5 小时前
多 Agent 架构到底怎么选?从 Claude Agent Teams、Cognition/Devin 到工程落地原则
前端·人工智能·后端