CommJS和ES规范的区别

227 阅读3分钟

CommonJS 与 ES 模块规范的区别

JavaScript 的模块化经历了从无到有的过程,CommonJSES 模块(ESM) 是两种主流的模块规范。它们的核心差异体现在设计目标、语法、运行机制和适用环境上。


1. 设计目标

CommonJSES 模块 (ESM)
为 Node.js 设计,解决服务器端模块化问题ECMAScript 官方标准,为浏览器和 Node.js 统一模块化方案
动态加载,适用于同步文件读取场景静态加载,支持编译时优化(如 Tree Shaking)

2. 语法对比

CommonJS

  • 导出模块
    // 导出单个值
    module.exports = function() { /* ... */ };
    
    // 导出多个值
    exports.a = 1;
    exports.b = 2;
    
  • 导入模块
    const lib = require('./lib'); // 同步加载
    const { a, b } = require('./lib');
    

ES 模块

  • 导出模块
    // 默认导出
    export default function() { /* ... */ };
    
    // 命名导出
    export const a = 1;
    export const b = 2;
    
  • 导入模块
    import lib from './lib.js'; // 静态导入
    import { a, b } from './lib.js';
    // 动态导入(返回 Promise)
    import('./lib.js').then(module => { /* ... */ });
    

3. 加载机制

CommonJSES 模块
动态加载require() 可在代码任意位置调用静态加载import 必须位于模块顶层
同步执行:模块加载时立即执行代码异步执行:模块解析与执行可分离
值的拷贝:导入的是模块导出的值的副本值的引用:导入的是模块导出的实时绑定

4. 运行时差异

CommonJS

  • 模块是对象module.exports 是一个普通对象,导出后不可变。
  • 循环依赖处理
    // a.js
    exports.x = 1;
    require('./b.js'); // 导入 b.js
    exports.x = 2;
    
    // b.js
    const a = require('./a.js');
    console.log(a.x); // 输出 1(未更新的值)
    

ES 模块

  • 模块是静态结构:导出的是值的引用,支持动态更新。
  • 循环依赖处理
    // a.js
    export let x = 1;
    import { y } from './b.js';
    x = 2;
    
    // b.js
    import { x } from './a.js';
    export let y = x; // y 会随 x 更新而变化
    

5. 环境支持

CommonJSES 模块
Node.js 默认模块系统浏览器原生支持(需 <script type="module">
不支持浏览器环境Node.js 从 v13.2.0 开始支持(需 .mjs 扩展名或 "type": "module"

6. 其他关键区别

特性CommonJSES 模块
顶层 this指向 module.exports指向 undefined
代码执行时机加载时立即执行预处理后按需执行
优化潜力动态加载难以静态分析支持 Tree Shaking、代码压缩优化
互操作性可通过 import() 加载 ESM需通过 require() 或工具转换

7. 如何选择?

  • Node.js 环境
    • 传统项目或需要动态加载时,使用 CommonJS
    • 新项目或需要跨平台兼容性时,优先选择 ES 模块
  • 浏览器环境
    • 必须使用 ES 模块(通过 Webpack 等工具也可转换 CommonJS)。

示例:混合使用两种模块

在 Node.js 中同时支持两种规范:

// 在 package.json 中设置 "type": "module"
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const fs = require('fs'); // 使用 CommonJS 模块

总结

  • CommonJS:简单灵活,适合服务器端同步场景,但缺乏静态优化。
  • ES 模块:标准化、静态化,支持跨平台和编译优化,是未来趋势。

根据项目需求选择合适的规范,现代工具链(如 Babel、Webpack)可无缝兼容两者。