37 # commonjs 规范流程梳理

news/2024/12/5 5:24:25/

require 源码大致过程

  1. mod.require 会默认调用 require 语法
  2. Module.prototype.require 模块的原型上有 require 方法
  3. Module._load 调用模块的加载方法,最终返回的是 module.exports
  4. Module._resolveFilename 解析文件名,将文件名变成绝对路径,默认尝试添加 .js .json
  5. Module._cache 默认会判断是否存在缓存
  6. new Module 创建模块(对象),里面有 id,exports
  7. Module._cache[filename] = module 把模块缓存起来,方便下次使用
  8. module.load 尝试加载模块
  9. module.paths 第三方模块查找的路径
  10. Module._extensions[extension] 获取当前模块的拓展名,策略是根据拓展名调用对应的方法
  11. fs.readFileSync 读取文件的内容
  12. module._compile 去除文本文件 BOM 头,编译文件的内容
  13. Module.wrap 将用户的内容包裹到一个函数中 (function (exports, require, module, __filename, __dirname) { }),用 vm.runInThisContext 创建沙箱环境,将字符串变成函数执行

简单实现一个自己的 require 去加载 js 文件


const path = require("path");
const fs = require("fs");
const vm = require("vm");function Module(id) {this.id = id;this.exports = {};
}
Module.warp = function (script) {let arr = [`(function (exports, require, module, __filename, __dirname) {`, script, `})`];return arr.join("");
};
// 加载策略
Module._extensions = {".js": function (module) {console.log("js---->", module);// 同步读取let content = fs.readFileSync(module.id, "utf-8");let fnStr = Module.warp(content);console.log("fnStr---->", fnStr);let fn = vm.runInThisContext(fnStr);console.log("fn---->", fn.toString());let exports = module.exports;let require = kaimoRequire;let __filename = module.id;let __dirname = path.dirname(module.id);// 改变 this 指向 exportsfn.call(exports, exports, require, module, __filename, __dirname);// 用户会给 module.exports 赋值},".json": function (module) {console.log("json---->", module);// 同步读取let content = fs.readFileSync(module.id, "utf-8");module.exports = JSON.parse(content);}
};// 把文件名变成绝对路径
Module._resolveFilename = function (filepath) {// 根据当前路径实现解析let filePath = path.resolve(__dirname, filepath);// 判断当前文件是否存在let exists = fs.existsSync(filePath);if (exists) return filePath;// 尝试添加后缀let keys = Object.keys(Module._extensions);for (let i = 0; i < keys.length; i++) {let currentPath = filePath + keys[i];// 尝试加载后缀查找if (fs.existsSync(currentPath)) {return currentPath;}}throw new Error("模块不存在");
};// 获取文件的后缀名进行加载
Module.prototype.load = function (filename) {let extname = path.extname(filename);Module._extensions[extname](this);
};// 缓存模块
Module.cache = {};// 加载模块
Module._load = function (filepath) {// 将路径转化成绝对路径let filename = Module._resolveFilename(filepath);console.log("filename---->", filename);// 获取路径后不要立即创建模块,先检查是否有缓存let cacheModule = Module.cache[filename];if (cacheModule) {return cacheModule.exports;}// 进行模块的创建,这里需要保证每个模块的唯一性,需要通过唯一路径进行查找let module = new Module(filename);// 缓存模块Module.cache[filename] = module;// 模块加载module.load(filename);return module.exports;
};// 自己实现的 require 方法
function kaimoRequire(filepath) {// 根据路径加载模块return Module._load(filepath);
}// 测试
let k = kaimoRequire("./37/a");console.log("测试 kaimoRequire 输出 k---->", k);

新建 a.js 文件

let name = "kaimo313";
console.log("okk");
module.exports = name;

在这里插入图片描述

总结

  1. require 语法是同步的,用的是 fs.readFileSync
  2. 最终 require 语法返回的是 module.exports
  3. 模块的 exports 和 module.exports 引用的是同一个变量
  4. 模块是动态加载的,每次 require 都会获取最新的导出的结果,可以将 require 写到条件中
  5. 更改 exports 的引用,不会导致 module.exports 的变化
  6. 循环引用的解决方案就是不循环引用,一般不会出现,如果出现只能加载部分数据

http://www.ppmy.cn/news/407082.html

相关文章

广告数仓:数仓搭建(二)

系列文章目录 广告数仓&#xff1a;采集通道创建 广告数仓&#xff1a;数仓搭建 广告数仓&#xff1a;数仓搭建(二) 文章目录 系列文章目录前言DWD层创建1.建表广告事件事实表 2.数据装载初步解析日志解析IP和UA标注无效流量编写脚本 总结 前言 这次我们完成数仓剩下的内容 D…

2345文件粉碎,文件强力删除工具无捆绑纯净提取版

前言 对比起其余文件粉碎工具来说&#xff0c;这款速度更快&#xff0c;成功率也更高&#xff0c;还是不错的 这里提供无捆绑并且纯净的2345文件粉碎工具&#xff0c;除去AvShellExt64.dll和AvShellExt.dll修改过几处十六进制&#xff0c;其余都是软件原版文件&#xff0c;可…

Unlocker - 文件粉碎工具

Unlocker 文件粉碎工具 上传安装包

粉碎文件BAT

粉碎文件BAT DEL /F /A /Q \\?\%1 RD /S /Q \\?\%1 看到很多粉碎文件的软件&#xff0c;要么重启后才能粉碎成功&#xff0c;要么就不能粉碎~有的粉碎文件软件甚至要你付钱。。。。其实&#xff0c;只要编36字节的代码就可以粉碎windows系统里的任何文件&#xff01;而且无用…

怎样用计算机粉碎文件夹,电脑粉碎文件用什么软件好,怎么彻底粉碎电脑文件...

想要把在电脑中的一些垃圾或是多余的软件删除时&#xff0c;经常会遇到这样的一种情况&#xff0c;就是有一些文件是无法彻底删除掉的&#xff0c;这些文件要么是显示系统正在运行中&#xff0c;要么就是因病毒等等删除起来比较费劲&#xff0c;在这里我将教大家一种比较简单的…

手机和电脑数据恢复,粉碎删除,电脑恢复文件教程

1. 只删除, 没有清空回收站. 这咱情况比较简单, 有一点电脑知识的朋友都知道, 文件还是存在的, 只不过躺在回收站而已. 只要到回收站把文件找出来拖回或还原就行了. 2. 删除文件后还清空了回收站 很多朋友碰到的就是这种情况&#xff0c;也是我们主要这中恢复误删文件的恢复. 清…

Promise、 Asyncawait 、setTimeOut执行顺序及区别

Promise、 Async/await 、setTimeOut执行顺序及区别 1、阐述 Promise是一种异步编程的解决方案&#xff0c;用于处理异步操作并返回结果或错误。Promise对象有三种状态&#xff1a;pending&#xff08;进行中&#xff09;、fulfilled&#xff08;已成功&#xff09;和rejected…

【Python 文件粉碎工具】——用python制作一款可以粉碎文件的软件工具,用文件恢复工具都找不回来,非常可靠

点个赞留个关注吧&#xff01;&#xff01; 文件粉碎工具&#xff1a;适用于粉碎密码文件和机密的escel表格等等&#xff0c;主要作用就是防止 别人用数据恢复大师把你刚删除的机密文件恢复过来&#xff0c;造成密码丢失等。 程序原理&#xff1a;修改内部数据&#xff0c;使用…