Appearance
第4章:Node.js 模块化开发
4.1 模块化是什么?
模块化是一种将代码拆分为独立、可复用单元的开发方式。在 Node.js 中,每个文件都是一个模块,模块之间通过 require() 和 module.exports 进行通信。
模块化的优势
- 代码复用:可以将通用功能封装为模块,在多个项目中复用
- 代码组织:将复杂代码拆分为多个小模块,提高代码可读性和可维护性
- 避免命名冲突:每个模块有自己的作用域,不会污染全局命名空间
- 依赖管理:清晰地管理模块之间的依赖关系
4.2 CommonJS 模块化规范
CommonJS 是 Node.js 默认采用的模块化规范,它定义了模块的导入和导出方式。
module.exports 导出模块
在 CommonJS 规范中,使用 module.exports 导出模块:
导出单个值:
javascript
// utils.js
const add = (a, b) => a + b;
module.exports = add;导出多个值:
javascript
// utils.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;
module.exports = {
add,
subtract,
multiply,
divide
};require() 导入模块
在 CommonJS 规范中,使用 require() 导入模块:
导入核心模块:
javascript
const fs = require('fs');
const http = require('http');导入自定义模块:
javascript
// 导入单个值
const add = require('./utils');
// 导入多个值
const utils = require('./utils');
console.log(utils.add(1, 2)); // 输出: 3
console.log(utils.subtract(5, 3)); // 输出: 2导入第三方模块:
javascript
const lodash = require('lodash');4.3 ES6 模块化规范
ES6 模块化规范使用 import 和 export 语法,Node.js 从 v13.2.0 开始支持 ES6 模块。
启用 ES6 模块
要在 Node.js 中使用 ES6 模块,需要:
- 将文件扩展名改为
.mjs - 或者在
package.json中设置"type": "module"
export 导出模块
导出单个值:
javascript
// utils.mjs
export const add = (a, b) => a + b;导出多个值:
javascript
// utils.mjs
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;默认导出:
javascript
// utils.mjs
const add = (a, b) => a + b;
export default add;import 导入模块
导入单个值:
javascript
// app.mjs
import { add } from './utils.mjs';
console.log(add(1, 2)); // 输出: 3导入多个值:
javascript
// app.mjs
import { add, subtract, multiply, divide } from './utils.mjs';
console.log(add(1, 2)); // 输出: 3
console.log(subtract(5, 3)); // 输出: 2导入默认值:
javascript
// app.mjs
import add from './utils.mjs';
console.log(add(1, 2)); // 输出: 3导入所有值:
javascript
// app.mjs
import * as utils from './utils.mjs';
console.log(utils.add(1, 2)); // 输出: 3
console.log(utils.subtract(5, 3)); // 输出: 24.4 自定义模块开发
示例:创建工具模块
步骤1:创建工具模块文件
创建 utils.js 文件:
javascript
// utils.js
/**
* 计算两个数的和
* @param {number} a - 第一个数
* @param {number} b - 第二个数
* @returns {number} 和
*/
const add = (a, b) => a + b;
/**
* 计算两个数的差
* @param {number} a - 被减数
* @param {number} b - 减数
* @returns {number} 差
*/
const subtract = (a, b) => a - b;
/**
* 计算两个数的积
* @param {number} a - 第一个数
* @param {number} b - 第二个数
* @returns {number} 积
*/
const multiply = (a, b) => a * b;
/**
* 计算两个数的商
* @param {number} a - 被除数
* @param {number} b - 除数
* @returns {number} 商
*/
const divide = (a, b) => {
if (b === 0) {
throw new Error('除数不能为0');
}
return a / b;
};
/**
* 生成指定范围的随机数
* @param {number} min - 最小值
* @param {number} max - 最大值
* @returns {number} 随机数
*/
const random = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
// 导出模块
module.exports = {
add,
subtract,
multiply,
divide,
random
};步骤2:使用工具模块
创建 app.js 文件:
javascript
// app.js
const utils = require('./utils');
// 使用工具函数
console.log('1 + 2 =', utils.add(1, 2));
console.log('5 - 3 =', utils.subtract(5, 3));
console.log('2 * 4 =', utils.multiply(2, 4));
console.log('8 / 2 =', utils.divide(8, 2));
console.log('1-10的随机数:', utils.random(1, 10));步骤3:运行程序
bash
node app.js输出结果:
1 + 2 = 3
5 - 3 = 2
2 * 4 = 8
8 / 2 = 4
1-10的随机数: 74.5 模块查找机制
当使用 require() 导入模块时,Node.js 会按照以下顺序查找模块:
- 核心模块:如果是核心模块(如 fs、http),直接返回核心模块
- 相对路径或绝对路径:如果路径以
./、../或/开头,按照路径查找文件 - node_modules:如果不是核心模块且没有指定路径,会在当前目录的
node_modules文件夹中查找 - 向上查找:如果当前目录的
node_modules中没有找到,会向上级目录的node_modules中查找,直到根目录
模块文件扩展名
当导入模块时,如果没有指定文件扩展名,Node.js 会按照以下顺序尝试添加扩展名:
.js.json.node(编译后的 C/C++ 模块)
目录模块
如果导入的是一个目录,Node.js 会在该目录中查找以下文件:
package.json文件中的main字段指定的文件index.jsindex.jsonindex.node
4.6 实操案例:封装工具模块
案例:创建日期工具模块
步骤1:创建日期工具模块
创建 dateUtils.js 文件:
javascript
// dateUtils.js
/**
* 格式化日期
* @param {Date} date - 日期对象
* @param {string} format - 格式字符串
* @returns {string} 格式化后的日期字符串
*/
const formatDate = (date, format = 'YYYY-MM-DD') => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return format
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds);
};
/**
* 获取当前日期
* @param {string} format - 格式字符串
* @returns {string} 当前日期字符串
*/
const getCurrentDate = (format = 'YYYY-MM-DD') => {
return formatDate(new Date(), format);
};
/**
* 计算两个日期之间的天数差
* @param {Date} date1 - 第一个日期
* @param {Date} date2 - 第二个日期
* @returns {number} 天数差
*/
const getDaysDifference = (date1, date2) => {
const oneDay = 24 * 60 * 60 * 1000;
const diffTime = Math.abs(date2 - date1);
return Math.floor(diffTime / oneDay);
};
/**
* 判断是否是闰年
* @param {number} year - 年份
* @returns {boolean} 是否是闰年
*/
const isLeapYear = (year) => {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
};
// 导出模块
module.exports = {
formatDate,
getCurrentDate,
getDaysDifference,
isLeapYear
};步骤2:使用日期工具模块
创建 app.js 文件:
javascript
// app.js
const dateUtils = require('./dateUtils');
// 使用日期工具函数
console.log('当前日期:', dateUtils.getCurrentDate());
console.log('当前时间:', dateUtils.getCurrentDate('YYYY-MM-DD HH:mm:ss'));
const date1 = new Date('2026-01-01');
const date2 = new Date('2026-01-10');
console.log('日期差:', dateUtils.getDaysDifference(date1, date2), '天');
console.log('2024年是闰年:', dateUtils.isLeapYear(2024));
console.log('2025年是闰年:', dateUtils.isLeapYear(2025));步骤3:运行程序
bash
node app.js输出结果:
当前日期: 2026-04-02
当前时间: 2026-04-02 03:16:00
日期差: 9 天
2024年是闰年: true
2025年是闰年: false小结
- 模块化是将代码拆分为独立、可复用单元的开发方式
- Node.js 默认使用 CommonJS 模块化规范
- CommonJS 使用
require()导入模块,使用module.exports导出模块 - ES6 模块化规范使用
import和export语法 - 自定义模块可以封装通用功能,提高代码复用性
- Node.js 有一套完整的模块查找机制,确保模块能够被正确找到
现在,你已经了解了 Node.js 的模块化开发,接下来让我们学习 npm 包管理工具。
