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

相关推荐
用户693717500138418 分钟前
Kimi K3 综合能力处于全球第一梯队
android·前端·后端
anno33 分钟前
Agent 新手 Skill 优先级指南:从第一套必装工作流,到专业能力补全
前端·后端
Liora_Yvonne1 小时前
前端请求层到底怎么封?为什么全局 axios 单例越用越难维护
前端
anno1 小时前
别再把文档“一刀切”:用 LangChain.js 做好 RAG 的第一公里
前端·后端
皮卡穆1 小时前
React 中使用 react-org-tree 实现组织结构树
前端·react.js·前端框架
MariaH1 小时前
费曼学习法与effort-learning理论
前端
qiaofugui1 小时前
如何用 Codex 做一次可靠的项目重构:方法、节奏和可复用提示词
前端
涛涛ing1 小时前
前端圈7月大地震:TS 7发布、Bun 11天从Zig迁Rust、Kimi K3登顶、大厂裁员50%
前端
遇乐的果园1 小时前
前端学习笔记-vue列表处理
前端·vue.js·学习