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)相互兼容。

相关推荐
渊不语16 小时前
Webpack 深入学习指南
前端·webpack
北京_宏哥16 小时前
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-38-屏幕截图利器-上篇(详细教程)
java·前端·面试
子兮曰16 小时前
🚀别再被JSON.parse坑了!这个深度克隆方案解决了我3年的前端痛点
前端·javascript·全栈
R瑾安16 小时前
VUE基础
前端·javascript·vue.js
无敌爆龙战士16 小时前
一文搞懂pnpm+monorepo的原理
前端
艾小码16 小时前
告别无效加班!这4个表单操作技巧,让你效率翻倍
前端·javascript·html
TimelessHaze17 小时前
面试必备:深入理解 Toast 组件的事件通信与优化实现
前端·trae
zayyo17 小时前
从 Promise 到 Generator,再到 Co 与 Async/Await 的演进
前端·javascript
我的写法有点潮17 小时前
这么全的正则,还不收藏?
前端·javascript