一. 模块查找
1. 绝对路径
- 根据绝对路径直接加载模块
- 因为访问文件需要使用绝对路径, 其他方式只是编写代码的便捷写法, 所以其他模块查找方法, 最终都会转换为绝对路径.
- ```javascript // require(“模块在系统中的绝对路径”)
require(“D:/Develop/demo/Node/src/a.js”)
或
require(“D:\Develop\demo\Node\src\a.js”)
<a name="8c19c5c4"></a>### 2. 相对路径 ./ 或 ../- 相对于当前模块- 转换为绝对路径- 加载模块-```javascript// require("模块相对路径")require("./src/a.js")
3. 相对路径
检查是否是内置模块, 如 fs, path 等
- node安装之后本身自带的模块
- 检查当前目录中的 node_modules
- 检查上级目录中的 node_modules
- 转换为绝对路径
- 加载模块
- ```javascript // require(“模块名称”)
// 例如: require(“abc”)
<a name="95dcab23"></a>### 4. 关于后缀名- 如果不提供后缀名, 则 node 会自动补全后缀名- js > json > node > mjs-```javascriptrequire("./src/a")
5. 关于文件名
- 如果仅提供目录, 不提供文件名, 则自动寻找该目录中的 index.js
package.json 中的 main 字段
- 表示包的默认入口
- 导入或执行包时若仅提供目录, 则使用 main 补全入口
- 默认值为 index.js
- node_mobules 中的模块三方库, 也相同
node ./
二. module 对象
- 记录了当前模块的信息
Module {id: '.', // 模块绝对路径, 如果是入口模块的话 id 为 ".", 而不是绝对路径path: 'D:\\Develop\\demo\\Node', // 模块的目录exports: {}, // 用于导出parent: null, // 被哪个模块使用filename: 'D:\\Develop\\demo\\Node\\index.js', // 模块的绝对路径loaded: false, // 模块是否加载完成children: [], // 子模块paths: ['D:\\Develop\\demo\\Node\\node_modules','D:\\Develop\\demo\\node_modules','D:\\Develop\\node_modules','D:\\node_modules'] // 记录了查找顺序}
三. require 函数
[Function: require] {// 将任何的路径写法转换为绝对路径 (不加载模块, 只是获取绝对路径字符串)resolve: [Function: resolve] { paths: [Function: paths] },// 主模块, 入口起点用的是哪个模块main: Module {id: '.',path: 'D:\\Develop\\demo\\Node',exports: {},filename: 'D:\\Develop\\demo\\Node\\index.js',loaded: false,children: [],paths: ['D:\\Develop\\demo\\Node\\node_modules','D:\\Develop\\demo\\node_modules','D:\\Develop\\node_modules','D:\\node_modules']},// 扩展名的处理函数extensions: [Object: null prototype] {'.js': [Function (anonymous)],'.json': [Function (anonymous)],'.node': [Function (anonymous)]},// 目前缓存的模块cache: [Object: null prototype] {'D:\\Develop\\demo\\Node\\index.js': Module {id: '.',path: 'D:\\Develop\\demo\\Node',exports: {},filename: 'D:\\Develop\\demo\\Node\\index.js',loaded: false,children: [],paths: [Array]}}}
四. 当执行一个模块或使用 require 时, 会将模块放置在一个函数环境中
myModule.js
- ```javascript console.log(‘当前模块路径 :>>’, dirname); console.log(‘当前模块文件 :>>’, filename); this.m = 5 exports.c = 3 module.exports = { a: 1, b: 2 }
// 被引用 输出 / 当前模块路径 :>> D:\Develop\demo\Node 当前模块文件 :>> D:\Develop\demo\Node\myModule.js result :>> { a: 1, b: 2 } /
console.log(‘当前模块路径 :>>’, dirname); console.log(‘当前模块文件 :>>’, filename); this.m = 5 module.exports.a = 1 module.exports.b = 2 exports.c = 3
// 被引用输出 / 当前模块路径 :>> D:\Develop\demo\Node 当前模块文件 :>> D:\Develop\demo\Node\myModule.js result :>> { m: 5, a: 1, b: 2, c: 3 } /
- 模拟 require-```javascript// 伪代码function require(modulePath) {// 1. 将 modulePath 转换为绝对路径 D:\Develop\demo\Node\myModule.js// 2. 判断是否该模块已有缓存if (require.cache = ["D:\\Develop\\demo\\Node\\myModule.js"]) {return require.cache = ["D:\\Develop\\demo\\Node\\myModule.js"].result}// 3. 读取文件内容console.log('当前模块路径 :>>', __dirname);console.log('当前模块文件 :>>', __filename);this.m = 5module.exports.a = 1module.exports.b = 2exports.c = 3// 4. 包裹到一个函数中function __temp(module, exports, require, __dirname, __filename) {console.log('当前模块路径 :>>', __dirname);console.log('当前模块文件 :>>', __filename);this.m = 5module.exports.a = 1module.exports.b = 2exports.c = 3}// 5. 创建 module 对象module.exports = {}const exports = module.exports__temp.call(module.exports, module, exports, require, module.path, module.filename) // 传入的 this 为 module.exportsreturn module.exports}require.catch = {};const result = require("./myModule")console.log("result :>>", result);console.log(this === module.exports); // trueconsole.log(this === exports); // true
注意:
- 不建议直接操作 “this” , 在实际编码当中
- 要么使用 “exports.属性”
- 要么使用 “module.exports = {}”
- this === exports === module.exports
