目录
一、为什么需要模块化?
在没有模块化之前,所有代码都写在一个文件里,项目一旦复杂,就会出现以下问题:
命名冲突:变量和函数容易被覆盖。
代码复用性差:想在另一个项目中复用部分代码不方便。
维护困难:文件过大,难以管理。
因此,模块化的出现就是为了解决 代码拆分、复用、依赖管理 等问题。
二、Node.js 的模块化规范
Node.js 主要支持两种模块化方式:
CommonJS (CJS) —— Node.js 原生支持的模块规范。
ES Module (ESM) —— ES6 引入的新标准,Node.js 在 v12+ 开始逐渐支持。
默认情况下,Node.js 使用 CommonJS 作为模块系统,但随着前端 ES6 普及,ESM 也逐渐成为趋势。
三、CommonJS 模块化
1. 基本语法
// 导出
const sum = (a, b) => a + b;
module.exports = sum;
// 导入
const sum = require('./sum.js');
console.log(sum(1, 2)); // 3
2. 特点
同步加载:模块在运行时加载(适合服务端)。
导出的是值拷贝:导出对象被缓存,多次引入不会重复执行模块代码。
动态导入:
require
可以写在代码的任意位置。
3. 缺点
只能在 Node.js 环境下使用,浏览器默认不支持。
同步加载在浏览器端会影响性能(需要打包工具来解决)。
四、ES6 模块(ESM)
1. 基本语法
// 导出
export const sum = (a, b) => a + b;
export default function multiply(a, b) {
return a * b;
}
// 导入
import multiply, { sum } from './math.js';
console.log(sum(1, 2)); // 3
console.log(multiply(2, 3)); // 6
2. 特点
编译时加载(静态加载):在代码执行前就确定模块依赖关系。
导出的是引用:导出变量值会随时更新。
严格模式:ESM 默认启用严格模式(
'use strict'
)。只能写在顶层:
import
/export
不能写在 if 或函数里。
3. 在 Node.js 中的使用
在 Node.js 中使用 ESM,需要满足以下条件之一:
package.json
中配置"type": "module"
。文件后缀为
.mjs
。
示例:
// package.json
{
"type": "module"
}
五、CommonJS 和 ES6 模块的区别
特点 | CommonJS (CJS) | ES6 Module (ESM) |
---|---|---|
语法 | require / module.exports |
import / export |
加载方式 | 运行时加载(同步) | 编译时加载(静态) |
导出值 | 值拷贝 | 引用绑定 |
执行时机 | 第一次加载时执行并缓存 | 静态分析阶段确定依赖 |
使用环境 | Node.js 原生支持 | 浏览器和 Node.js(需配置) |
动态导入 | 支持(require 可写在任意位置) |
通过 import() 函数支持 |
六、实际开发中的选择
Node.js 项目:目前大多数依旧采用 CommonJS,但一些新项目已经迁移到 ESM。
前端项目:浏览器环境天然支持 ESM,更加推荐使用 ES6 模块。
混合使用:如果项目中既有 CommonJS 又有 ESM,可以通过
import()
或require
来桥接,但推荐统一使用一种。
七、总结
CommonJS:Node.js 的传统模块化方案,运行时加载,值拷贝,适合后端。
ES6 Module:现代模块化标准,静态分析,引用绑定,更适合前端,也逐渐在 Node.js 中普及。
在长期发展趋势下,ESM 将成为统一标准,未来前后端都会逐步过渡到 ES6 模块化。