模块的查找
require()中路径的几种写法
绝对路径
require('e:\\系统默认\\桌面\\node\\模块化细节\\index.js');
项目目录
当你在vscode中使用runcode时你会发现它执行的命令就是 node “绝对路径”
其他路径的写法都会转换为绝对路径,导入模块就是读取文件,读取文件是需要绝对路径的
相对路径
require('./');
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
module对象
记录啦当前模块的信息-包括模块被谁引用的,目前我这个模块又引用啦那些子模块以及模块id
打印结果为:
require
resolve 函数
它会将模块路径转化为绝对路径 他并没有加载模块只是将模块路径转化为绝对路径
如下图
当执行一个模块或使用require时,会将模块放置在一个函数环境中
问题1
当a.js的代码
exports.a = 'a'
module.exports.b = 2;
module.exports.c = 3;
this.d = 4;
在入口文件导入a.js并将其打印出来
const res = require('./a')
console.log(res)
问题2
当我把a.js代码做如下修改
exports.a = 'a'
module.exports = {
b: 2,
c: 3,
}
this.d = 4;
解析
这与require函数有关也就是标题的:当执行一个模块或使用require时,会将模块放置在一个函数环境中
我们用伪代码实现一下require
function require(modulePath) {
//1. 将modulePath转换为绝对路径:D:\repository\NodeJS\源码\myModule.js
//2. 判断是否该模块已有缓存
// if(require.cache["D:\\repository\\NodeJS\\源码\\myModule.js"]){
// return require.cache["D:\\repository\\NodeJS\\源码\\myModule.js"].result;
// }
//3. 读取文件内容
//4. 包裹到一个函数中
function __temp(module, exports, require, __dirname, __filename) {
console.log("当前模块路径:", __dirname);
console.log("当前模块文件:", __filename);
exports.a = 'a'
module.exports = {
b: 2,
c: 3
};
this.d = 4;
}
//6. 创建module对象
module.exports = {};
const exports = module.exports;
__temp.call(module.exports, module, exports, require, module.path, module.filename)
return module.exports;
}
这就与问题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 ,那结果还用想吗