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

相关推荐
用户4794928356915几秒前
改了CSS刷新没反应-你可能不懂HTTP缓存
前端·javascript·面试
还好还好不是吗17 分钟前
老项目改造 vue-cli 2.6 升级 rsbuild 提升开发效率300% upupup!!!
前端·性能优化
sumAll19 分钟前
别再手动对齐矩形了!这个开源神器让 AI 帮你画架构图 (Next-AI-Draw-IO 体验)
前端·人工智能·next.js
OpenTiny社区20 分钟前
2025OpenTiny星光ShowTime!年度贡献者征集启动!
前端·vue.js·低代码
wangan09431 分钟前
不带圆圈的二叉树
java·前端·javascript
狗哥哥32 分钟前
从零到一:打造企业级 Vue 3 高性能表格组件的设计哲学与实践
前端·vue.js·架构
疯狂平头哥35 分钟前
微信小程序真机预览-数字不等宽如何解决
前端
Drift_Dream36 分钟前
前端趣味交互:如何精准判断鼠标从哪个方向进入元素?
前端
hqk38 分钟前
鸿蒙ArkUI:状态管理、应用结构、路由全解析
android·前端·harmonyos
米思特儿林1 小时前
NuxtImage 配置上传目录配置
前端