模块的查找

require()中路径的几种写法

绝对路径

  1. require('e:\\系统默认\\桌面\\node\\模块化细节\\index.js');

项目目录
image.png
当你在vscode中使用runcode时你会发现它执行的命令就是 node “绝对路径”
image.png
其他路径的写法都会转换为绝对路径,导入模块就是读取文件,读取文件是需要绝对路径的

相对路径

  1. require('./');
  2. require('../');

相对于当前路径, 也就是平常我们导入模块的方式, 最终会转化为绝对路径来加载模块

只写模块名导入模块

node会首先检查师是否为内置模块
例如webpack中常用的路径 const path = require('path') 这个就是内置模块
如果不是内置模块他会查找当前目录中的 node_modules 文件
当前目录中找不到会去上级目录查找node_modules 文件
当找到啦所需要的模块后转化为绝对路径
最终会加载模块
当找不到会进行报错

自动补全后缀名补全

它是怎吗补全的呢?
补全后缀名的顺序为 js json node mjs
它会优先去查找模块名.js 当找不到会去把后缀名替换为json重新查找以此类推

只提供文件名

如果只提供目录,不提供文件名,则自动寻找该目录中的index.js
package.json中的main字段

  • 你会发现有些包中是存在package.json文件,该文件中的main字段表示为包的默认入口
  • 导入或执行包时若仅提供目录,则使用main补全入口
  • main字段的默认值为 index.js

image.png

module对象

记录啦当前模块的信息-包括模块被谁引用的,目前我这个模块又引用啦那些子模块以及模块id
image.png
image.png
打印结果为:
image.png

require

image.png
image.png

resolve 函数

image.png
它会将模块路径转化为绝对路径 他并没有加载模块只是将模块路径转化为绝对路径
如下图
image.png

当执行一个模块或使用require时,会将模块放置在一个函数环境中

问题1

当a.js的代码

  1. exports.a = 'a'
  2. module.exports.b = 2;
  3. module.exports.c = 3;
  4. this.d = 4;

在入口文件导入a.js并将其打印出来

  1. const res = require('./a')
  2. console.log(res)

打印结果
image.png

问题2

当我把a.js代码做如下修改

  1. exports.a = 'a'
  2. module.exports = {
  3. b: 2,
  4. c: 3,
  5. }
  6. this.d = 4;

打印结果为
image.png
这是为啥?

解析

这与require函数有关也就是标题的:当执行一个模块或使用require时,会将模块放置在一个函数环境中
我们用伪代码实现一下require

  1. function require(modulePath) {
  2. //1. 将modulePath转换为绝对路径:D:\repository\NodeJS\源码\myModule.js
  3. //2. 判断是否该模块已有缓存
  4. // if(require.cache["D:\\repository\\NodeJS\\源码\\myModule.js"]){
  5. // return require.cache["D:\\repository\\NodeJS\\源码\\myModule.js"].result;
  6. // }
  7. //3. 读取文件内容
  8. //4. 包裹到一个函数中
  9. function __temp(module, exports, require, __dirname, __filename) {
  10. console.log("当前模块路径:", __dirname);
  11. console.log("当前模块文件:", __filename);
  12. exports.a = 'a'
  13. module.exports = {
  14. b: 2,
  15. c: 3
  16. };
  17. this.d = 4;
  18. }
  19. //6. 创建module对象
  20. module.exports = {};
  21. const exports = module.exports;
  22. __temp.call(module.exports, module, exports, require, module.path, module.filename)
  23. return module.exports;
  24. }

这就与问题2想对应,_temp韩式执行时this指向modul.exports 但是内部函数有一个modul.exports肯定会用最近的也就是函数内部的modul.exports
问题1 中_temp 函数内部并没有modul.exports,而this指向的就是modul.exports,而_temp函数内部执行的读取到的模块代码,this.d = 4 而this指向modul.exports,而modul.exports === exports ,那结果还用想吗