Skip to content

commonjs 和 esm 的区别

CommonJS 和 ESM(ES Modules)是 JavaScript 中最常用的两种模块规范,二者有明显的区别:

一、定义上的区别

规范描述使用场景
CommonJSNode.js 最初设计的模块标准Node.js 环境
ESM(ES Modules)ECMAScript 官方的模块标准浏览器、现代 Node.js

二、语法区别

CommonJS:

  • 使用 require 引入模块。
  • 使用 module.exportsexports 导出内容。
js
// 导入模块
const lodash = require("lodash");

// 导出模块
module.exports = {
  add(a, b) {
    return a + b;
  },
};

ES Modules:

  • 使用 import 引入模块。
  • 使用 exportexport default 导出内容。
js
// 导入模块
import lodash from "lodash";

// 导出模块
export const add = (a, b) => a + b;

// 默认导出
export default function multiply(a, b) {
  return a * b;
}

三、加载时机的差别

特性CommonJSESM
加载时机运行时(同步)编译时(静态分析)
加载机制模块整体加载支持按需加载,动态 import
  • CommonJS 模块运行时加载

    • 每次导入模块都会执行完整模块代码,导出对象的拷贝。
  • ES Modules 模块静态加载

    • 编译时就确定依赖关系,可进行 tree-shaking 优化。
    • 支持动态导入(import())。

四、模块缓存方式

特性CommonJSESM
缓存✅ 首次加载后缓存✅ 模块实例化后缓存
  • CommonJS

    • 首次加载后,会缓存模块结果,多次引用同一模块返回同一个实例。
  • ES Modules

    • 同样具有缓存机制,但静态分析可进一步优化,避免未使用代码加载。

五、值传递方式

特性CommonJSESM
传递方式值的拷贝绑定引用(live bindings)
  • CommonJS 导出的是值的副本,修改原模块导出变量,不会影响导入方:
js
// CommonJS 导出模块
let count = 0;
module.exports = { count };

// 导入
const mod = require("./mod.js");
mod.count = 5; // 不影响原模块的值
  • ES Modules 导出的是引用绑定(实时绑定):
js
// ESM 导出模块
export let count = 0;
export function increment() {
  count++;
}

// 导入
import { count, increment } from "./mod.js";
increment();
console.log(count); // 实时更新

六、浏览器与 Node.js 支持程度

环境CommonJSESM
浏览器❌ 原生不支持✅ 原生支持
Node.js(旧版)✅ 原生支持❌ 需额外配置
Node.js(新版)✅ 支持(默认)✅ 支持(需.mjs 或 type=module)
  • 浏览器原生只支持 ESM,CommonJS 需打包工具(如 Webpack)。
  • Node.js 新版同时支持,但 ESM 需额外标记或后缀(.mjspackage.jsontype: "module")。

七、使用场景对比总结

特性CommonJSESM (ES Modules)
使用场景Node.js(服务器端)浏览器、现代 JavaScript 开发
性能优化较差,不能 Tree-Shaking更好,支持 Tree-Shaking
加载机制运行时加载,动态同步加载编译时加载,支持动态异步加载
生态支持成熟、广泛逐渐成为主流,支持逐渐完善

八、实战应用建议:

  • 前端项目:推荐 ESM,更加现代化,支持浏览器原生,构建优化能力强。

  • Node.js 项目

    • 旧项目和生态库广泛使用 CommonJS。
    • 新项目推荐逐步迁移到 ESM,以利用更好的性能优化与开发体验。

🔖 总结表格

区别点CommonJSES Modules (ESM)
模块规范Node.js 标准ECMAScript 官方标准
加载方式运行时加载编译时静态加载
导出导入语法require/module.exportsimport/export
值传递值拷贝引用绑定(live bindings)
Tree-Shaking 支持
浏览器支持需打包工具原生支持
动态导入不支持(同步加载)支持(import())

以上明确了 CommonJS 与 ESM 在使用方式、性能和环境上的差异,这类问题通常作为前端开发或 Node.js 开发的重要基础面试题。