Node.js模块系统
写代码最怕啥?就是一个文件堆所有东西,到后面自己都看不懂了。好在Node.js有模块系统帮你撑腰!这节课我们来聊聊怎么把代码拆分成一个个小模块,让你的项目整整齐齐、易维护。
一、 为什么要用模块
想象一下,你要开发一个博客系统:
- 用户管理模块
- 文章管理模块
- 评论模块
- 上传图片模块
如果全塞在一个app.js里,估计有上万行,看都看不过来。拆分成独立模块后:
- user.js - 用户相关
- article.js - 文章相关
- comment.js - 评论相关
- upload.js - 上传相关
是不是清晰多了?
二、 两种模块类型
Node.js有两种模块:
1. 内置模块(原生模块)
Node.js自带的核心模块,直接引用就能用:
// 引入文件系统模块 const fs = require('fs');
// 引入路径模块 const path = require('path');
// 引入http模块 const http = require('http');
2. 自定义模块
你自己写的模块:
// 引入自己写的math.js const math = require('./math');
注意哈,引入自定义模块要加 "./" ,表示当前目录。
三、 module.exports 导出模块
这是最常用的方式。先创建一个 math.js 文件:
// math.js function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) { if (b === 0) { return '不能除以0!'; } return a / b; }
// 导出多个函数 module.exports = { add, subtract, multiply, divide };
然后在另一个文件里使用:
// app.js const math = require('./math');
console.log(math.add(1, 2)); // 输出: 3 console.log(math.subtract(5, 3)); // 输出: 2 console.log(math.multiply(3, 4)); // 输出: 12 console.log(math.divide(10, 2)); // 输出: 5
四、 exports 简写
还有一种更简洁的写法:
// person.js exports.name = '小明'; exports.age = 18; exports.sayHello = function() { return '大家好,我是' + this.name; };
使用:
const person = require('./person'); console.log(person.name); // 小明 console.log(person.sayHello()); // 大家好,我是小明
不过要注意,exports 只能导出对象属性。如果要导出一个函数或者整个变量,得用 module.exports。
五、 模块加载顺序
Node.js加载模块时有套路:
- 先看是不是内置模块(fs, path, http这些)
- 再看是不是 node_modules 里的第三方包
- 最后看是不是自定义模块(./开头的)
// 这个会先找内置的 fs const fs = require('fs');
// 这个会找 node_modules 里的 express const express = require('express');
// 这个找当前目录下的 user.js const user = require('./user');
六、 实战:做一个计算器模块
来,我们做个完整的例子。
第1步:创建 calculator.js
// calculator.js class Calculator { constructor(name) { this.name = name; }
add(a, b) { return a + b; }
subtract(a, b) { return a - b; }
multiply(a, b) { return a * b; }
divide(a, b) { if (b === 0) return '错误:不能除以0'; return a / b; }
// 打印结果 printResult(operation, a, b, result) { console.log(this.name + ': ' + a + ' ' + operation + ' ' + b + ' = ' + result); } }
module.exports = Calculator;
第2步:创建 main.js
// main.js const Calculator = require('./calculator');
// 创建计算器实例 const calc = new Calculator('我的计算器');
// 做几道题 const result1 = calc.add(10, 5); calc.printResult('+', 10, 5, result1);
const result2 = calc.multiply(3, 7); calc.printResult('*', 3, 7, result2);
const result3 = calc.divide(20, 4); calc.printResult('/', 20, 4, result3);
运行 node main.js,输出:
我的计算器: 10 + 5 = 15 我的计算器: 3 * 7 = 21 我的计算器: 20 / 4 = 5
七、 模块的小坑
1. 循环引用
A引用B,B又引用A,这种情况Node.js能处理,但要注意别死循环:
// a.js console.log('a 开始'); const b = require('./b'); console.log('a 结束');
// b.js console.log('b 开始'); const a = require('./a'); console.log('b 结束');
输出是: a 开始 b 开始 b 结束 a 结束
Node.js会返回一个部分加载的对象,不会死循环。
2. 路径写错
// 错误写法 const foo = require('foo'); // 找不到会报错
// 正确写法 const foo = require('./foo'); // 当前目录 const bar = require('../bar'); // 上级目录
3. 忘了加 .js 后缀
Node.js会自动补全,但最好还是写清楚:
// 这些都行 require('./user') require('./user.js') require('./user.json')
八、 下节预告
这节课我们学了模块系统,下一节我们来聊聊npm这个大杀器,学完你就知道什么叫"站在巨人的肩膀上"——别人写好的代码直接拿来用!
有问题评论区见!