JavaScript 模块导入导出方式详解:CommonJS、ESModule 及动态导入
URL: https://juejin.cn/post/7519334402688024603
Summary: 一、CommonJS 模块系统 CommonJS 是 Node.js 默认采用的模块系统,主要用于服务器端 JavaScript。 1. 导出方式 (1) 导出单个值 (2) 导出多个值 2. 导入方
导出工具:https://webink.app/ 导出工号:openClaw
JavaScript 模块导入导出方式详解:CommonJS、ESModule 及动态导入
作者:梨子同志
发布时间:2025-06-24
阅读时间:3 分钟
标签:前端
一、CommonJS 模块系统
CommonJS 是 Node.js 默认采用的模块系统,主要用于服务器端 JavaScript。
1. 导出方式
(1) 导出单个值
javascript
// 方式 1:直接赋值给 module.exports
module.exports = function() {
console.log('Hello from CommonJS');
};
// 方式 2:先定义后赋值
const myFunction = () => {
console.log('Hello from CommonJS');
};
module.exports = myFunction;(2) 导出多个值
javascript
// 方式 1:导出对象
module.exports = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
// 方式 2:逐个添加属性
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;
// 注意:不能直接给 exports 赋值,这会断开与 module.exports 的链接
// 错误示例:exports = { add, subtract };2. 导入方式
(1) 导入整个模块
javascript
const math = require('./math.js');
console.log(math.add(2, 3)); // 5(2) 解构导入
javascript
const { add, subtract } = require('./math.js');
console.log(add(2, 3)); // 5(3) 导入核心模块
javascript
const fs = require('fs');
const path = require('path');(4) 导入 JSON 文件
javascript
const config = require('./config.json');(5) 导入目录(自动查找 index.js)
javascript
const myModule = require('./my-module-dir');二、ES Module (ESM) 模块系统
ES Module 是 ECMAScript 标准模块系统,现代浏览器和 Node.js 都支持。
1. 导出方式
(1) 命名导出 (Named Exports)
javascript
// 方式 1:声明时直接导出
export const name = 'Alice';
export function greet() {
console.log('Hello from ESM');
}
// 方式 2:先定义后统一导出
const age = 30;
const sayHello = () => console.log('Hi');
export { age, sayHello };
// 方式 3:导出时重命名
export { age as userAge, sayHello as greet };(2) 默认导出 (Default Export)
javascript
// 每个模块只能有一个默认导出
// 方式 1:直接默认导出
export default function() {
console.log('Default export');
}
// 方式 2:先定义后默认导出
const myComponent = () => console.log('My Component');
export default myComponent;
// 方式 3:默认导出对象
export default {
version: '1.0',
author: 'Alice'
};(3) 混合导出
javascript
export const version = '1.0';
export default function main() {
console.log('Main function');
}2. 导入方式
(1) 导入命名导出
javascript
import { name, greet } from './module.js';
import { name as userName, greet as sayHello } from './module.js';(2) 导入默认导出
javascript
import mainFunction from './module.js';
import myDefault from './module.js';(3) 混合导入
javascript
import mainFunction, { version } from './module.js';(4) 导入所有导出
javascript
import * as module from './module.js';
console.log(module.version);
module.default();(5) 仅执行模块(不导入任何内容)
javascript
import './module.js'; // 适用于有副作用的模块三、动态导入 (Dynamic Imports)
动态导入允许在运行时按需加载模块,返回 Promise。
1. CommonJS 动态导入
CommonJS 的 require 本身就是动态的,可以在任何地方使用:
javascript
// 条件加载
if (condition) {
const module = require('./moduleA');
} else {
const module = require('./moduleB');
}
// 动态路径
const path = someCondition ? './moduleA' : './moduleB';
const module = require(path);2. ES Module 动态导入
ESM 使用 import() 函数实现动态导入:
(1) 基本用法
javascript
import('./module.js')
.then(module => {
module.default();
console.log(module.version);
})
.catch(err => {
console.error('模块加载失败', err);
});(2) 结合 async/await
javascript
async function loadModule() {
try {
const module = await import('./module.js');
module.greet();
} catch (error) {
console.error('加载失败', error);
}
}(3) 动态路径
javascript
const lang = getUserLanguage();
import(`./locales/${lang}.js`)
.then(module => {
// 使用本地化模块
});(4) 多个模块并行加载
javascript
Promise.all([
import('./moduleA.js'),
import('./moduleB.js')
]).then(([moduleA, moduleB]) => {
// 使用两个模块
});3. 动态导入的应用场景
- 代码分割:减少初始加载体积
- 按需加载:只在需要时加载模块
- 条件加载:根据不同环境/条件加载不同模块
- 路由级加载:SPA 中的路由懒加载
- Polyfill 加载:根据浏览器特性动态加载
四、CommonJS 与 ES Module 互操作
1. 在 CommonJS 中加载 ESM
Node.js 中必须使用动态 import():
javascript
// commonjs 文件
(async () => {
const esModule = await import('./es-module.mjs');
esModule.someFunction();
})();2. 在 ESM 中加载 CommonJS
可以直接使用 import 语法:
javascript
// esm 文件
import cjsModule from './commonjs-module.cjs';
console.log(cjsModule.someValue);
// CommonJS 的 module.exports 会作为默认导出
import { namedExport } from './commonjs-module.cjs'; // 错误!不能这样解构
// 正确方式:先导入默认,再解构
import cjsModule from './commonjs-module.cjs';
const { namedExport } = cjsModule;五、最佳实践建议
- 新项目:优先使用 ES Module
- Node.js 项目:
- 新项目设置
"type": "module" - 旧项目继续使用 CommonJS 或逐步迁移
- 新项目设置
- 浏览器项目:
- 使用打包工具处理模块
- 或直接使用
<script type="module">(现代浏览器)
- 动态导入:
- 性能敏感场景使用代码分割
- 注意错误处理
- 模块设计:
- 保持模块功能单一
- 合理使用默认导出和命名导出
- 避免复杂的循环依赖
六、关键区别总结
| 特性 | CommonJS | ES Module |
|---|---|---|
| 加载方式 | 同步 | 异步 |
| 语法 | require/module.exports | import/export |
| 动态导入 | 原生支持 | 使用 import() 函数 |
| 加载时机 | 运行时 | 编译时静态分析 |
| 值传递 | 值拷贝 | 值引用(实时绑定) |
顶层 this | 指向 module.exports | 指向 undefined |
| 主要环境 | Node.js | 浏览器和现代 Node.js |
本文整理自稀土掘金文章