Node.js 模块系统:CommonJS vs ES Modules

Node.js 模块系统:CommonJS vs ES Modules

理解两种模块系统的区别和使用场景

概述

Node.js 支持两种模块系统:

特性 CommonJS ES Modules
关键字 require / module.exports import / export
加载方式 运行时同步加载 编译时静态加载
文件扩展名 .js .mjs.cjs
Node.js 支持 默认支持 v13.2+ 稳定支持

CommonJS (CJS)

导出

javascript 复制代码
// math.js

// 方式1:导出单个值
module.exports = function add(a, b) {
  return a + b;
};

// 方式2:导出多个属性
module.exports.add = function(a, b) { return a + b; };
module.exports.subtract = function(a, b) { return a - b; };

// 方式3:使用 exports(注意:不能直接赋值)
exports.PI = 3.14159;
exports.multiply = function(a, b) { return a * b; };

导入

javascript 复制代码
// app.js

// 导入整个模块
const math = require('./math');
console.log(math.add(1, 2));

// 解构导入
const { add, PI } = require('./math');
console.log(PI);

// 导入内置模块
const fs = require('fs');
const path = require('path');

// 导入第三方模块
const express = require('express');

package.json 配置

json 复制代码
{
  "type": "commonjs"  // 默认,可省略
}

ES Modules (ESM)

导出

javascript 复制代码
// math.js 或 math.mjs

// 命名导出
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

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

// 或者集中导出
const PI = 3.14159;
const add = (a, b) => a + b;
export { PI, add };

导入

javascript 复制代码
// app.js 或 app.mjs

// 默认导入
import add from './math.js';

// 命名导入
import { add, subtract, PI } from './math.js';

// 重命名导入
import { add as sum } from './math.js';

// 导入所有
import * as math from './math.js';

// 副作用导入(只执行,不导入)
import './polyfill.js';

package.json 配置

json 复制代码
{
  "type": "module"
}

或使用 .mjs 扩展名(自动启用 ESM)


主要区别

1. 加载时机

javascript 复制代码
// CommonJS - 运行时加载
const math = require('./math');  // 同步执行

// ES Modules - 编译时加载
import { add } from './math';    // 静态分析

2. 导出方式

javascript 复制代码
// CommonJS - 值拷贝
let count = 0;
module.exports = { count };
count = 1;  // 导出值不变,仍是 0

// ES Modules - 动态引用
export let count = 0;
count = 1;  // 导出值同步更新为 1

3. this 指向

javascript 复制代码
// CommonJS - this 指向 module.exports
console.log(this === module.exports);  // true

// ES Modules - this 是 undefined
console.log(this);  // undefined

实战示例

CommonJS 项目结构

复制代码
project/
├── package.json (默认 commonjs)
├── utils/
│   └── math.js
└── app.js
javascript 复制代码
// utils/math.js
module.exports.add = (a, b) => a + b;

// app.js
const { add } = require('./utils/math');
console.log(add(1, 2));

ES Modules 项目结构

复制代码
project/
├── package.json ("type": "module")
├── utils/
│   └── math.js
└── app.js
javascript 复制代码
// utils/math.js
export const add = (a, b) => a + b;

// app.js
import { add } from './utils/math.js';
console.log(add(1, 2));

混用技巧

在 CJS 中使用 ESM

javascript 复制代码
// 需要 dynamic import
async function loadModule() {
  const { add } = await import('./math.mjs');
  return add(1, 2);
}

在 ESM 中使用 CJS

javascript 复制代码
// 可以直接导入
import express from 'express';
import { readFile } from 'fs';

选择建议

使用 CommonJS 当:

  • 需要动态加载模块
  • 兼容旧项目或工具
  • 编写简单的脚本工具

使用 ES Modules 当:

  • 开始新项目
  • 使用现代前端框架(React、Vue)
  • 需要_tree-shaking_ 优化
  • 编写可同时在浏览器和 Node.js 运行的代码

快速参考

javascript 复制代码
// CommonJS
module.exports = { value: 1 };
const { value } = require('./file');

// ES Modules
export const value = 1;
import { value } from './file.js';

总结

  • CommonJS:Node.js 传统方式,成熟稳定
  • ES Modules:现代标准,未来趋势
相关推荐
大家的林语冰31 分钟前
Node 2026 发布,JS 三大新功能上线,最后一个奇偶版本
前端·javascript·node.js
Aolith3 小时前
从裸奔到加固:我的校园论坛网络安全实战
node.js·全栈
晓杰'9 小时前
Balatro后端进阶(1):自定义NestJS WebSocket Adapter实现消息拦截
后端·websocket·typescript·node.js·游戏开发·nestjs·wsadapter
zyl8372111 小时前
Express快速上手
https·node.js·express
梦无矶11 小时前
nrm自动设置npm镜像源
前端·npm·node.js
网络点点滴11 小时前
Node.js的核心:事件循环
node.js
zyl8372112 小时前
Node.js 安装
node.js
梦无矶12 小时前
快速设置npm默认源为国内全局镜像源
前端·npm·node.js
王木风1 天前
终端里的编程副驾:DeepSeek-TUI-项目深度拆解,实测与原理分析
linux·运维·人工智能·rust·node.js