commonjs的本质

js 复制代码
this.a = 1;
exports.b = 2;

exports = {
  c: 3
}

module.exports = {
  d: 4,
};

exports.e = 5;

this.f = 6;

接下来理解 commonjs的本质,理解 commonjs的本质,什么题目都不难。

commonjs是一个模块化的标准,任何一个js文件,都是一个模块,每个模块有自己的导出结果。

我们要使用一个模块的时候,是不是要通过一个require函数,把模块路径传给他。

js 复制代码
const r = require('./2');
console.log(r);

那么这个函数一运行。这个函数一运行,是不是相当于是在运行这个模块。运行完成之后,这个函数还有一个返回结果。那么这个返回结果,拿到就是这个模块导出的结果。

要理解commonjs,就要理解require函数。它到底是怎么运行的,做了啥事,为什么这里的结果就是这里的导出结果。导出到底又是啥,这一切的疑团都在require函数的内部。那这个require函数是怎么写的呢,它这个是node在本地实现的。

写伪代码,逻辑大致相同。

js 复制代码
function require(modulePath) {
  // 1. 根据传递的模块路径,得到模块完整地绝对路径
  var moduleId = getModuleId(modulePath);
  
  // 2. 判断缓存
  if (cache[moduleId]) {
    return cache[moduleId];
  }
  
  // 3. 真正运行模块代码的辅助函数
  function _require(exports, require, module, __filename, __dirname) {
    // 目标模块的代码在这里
    // ...
  }
  
  // 4. 准备并运行辅助函数
  var module = {
    exports: {},
  };
  
  var exports = module.exports;
  
  // 得到模块文件的绝对路径
  var __filename = moduleId;
  // 得到模块所在目录的绝对路径
  var __filename = moduleId;
  // 得到模块所在目录的绝对路径
  var __dirname = getDirname(__filename);
  _require.call(exports, exports, require, module, __filelname, __dirname);
  
  // 5. 缓存 module.exports
  cache[moduleId] = module.exports;
  
  // 6. 返回 module.exports
  return module.exports;
}
js 复制代码
const r = require('./2');
console.log(r);

这就是整个 require 函数的 伪代码,看上去呢, 挺复杂。其实非常简单,

把整个的结果,放到一个函数里边。函数里边直接放置模块代码。

也就是说

js 复制代码
this.a = 1;
exports.b = 2;

exports = {
  c: 3
}

module.exports = {
  d: 4,
};

exports.e = 5;

this.f = 6;

这段代码一定是在函数里边,是函数一定要有一个arguments这么一个东西。全局里面没有,只有在函数里面才有。

真的能打印出来,说明啥,说明它在一个函数里边。

这个函数会给它传5个参数。

js 复制代码
function _require(exports, require, module, __filename, __dirname) {

}

再来打印一下arguments的长度。

js 复制代码
console.log(arguments.length);
  • exports
  • require
  • module
  • __filename
  • __dirname // 这个模块的目录的绝对路径

为什么在文件里面都可以直接使用,因为这5个它们都是参数。

有的用node的esmodule,然后这5个参数都不能用了。因为它不在一个函数环境里面了。

知识就是越深入越复杂,越深入越复杂,当深入到一定程度之后,反而变得更简单了。

反之,没有触碰到本质,那就是各种规则,要记exports表示啥意思,module.exports表达啥意思。要记各种各样的规则。

之后就是调用__require这个函数,调用的时候要准备好这5个参数。require参数就是require本身这个函数。

js 复制代码
var module = {
  exports: {},
}

var exports = module.exports;

module.exports 和 exports 是同一个东西。

__filename表示文件的绝对路径。

js 复制代码
var exports = module.exports; // 这就是模块的id

模块所在目录的绝对路径,通过内置模块就能够完成。

js 复制代码
// 得到模块文件的绝对路径
var __filename = moduleId;

// 得到模块所在目录
var __dirname = getDirname(__filename)

_require.call(exports, exports, require, module,  __filename, __dirname);

// 5. 缓存 module.exports
cache[moduleId] = module.exports;

// 6. 返回 module.exports
return module.exports;

this 和 exports 和 module.exports 是一个东西。一开始都指向同一个对象,都指向一个空对象。

yaml 复制代码
{ a: 1, b: 2, f: 6 }

exports
{ c: 3, e: 5 }

module.exports
{ d: 4 }

require函数最后返回的是module.exports。(从函数可以见得)。

相关推荐
IT_陈寒36 分钟前
Java中equals方法比了个寂寞?原来这才是正确的重写姿势
前端·人工智能·后端
默_笙36 分钟前
🚓 分诊台与拆题术:让 RAG 学会判断和规划
前端·javascript
CopyCode36 分钟前
用 AI 迁项目有多爽?我把 Webpack 迁 Vite 的全过程记下来了
前端·架构
去伪存真36 分钟前
Electron 自动化发布指南:GitHub Actions 跨平台打包全纪录
前端·electron
计算机魔术师37 分钟前
OpenAI智能体失控闯进美国政府网站,53张用户图片外泄背后
前端
颜进强37 分钟前
14 · NestJS ExecutionContext 执行上下文:守卫、拦截器、过滤器拿到的"同一个 context",为什么能力不一样?
前端·后端·ai编程
程序员Flycan37 分钟前
🚀 跨域终结者:前端代理服务器(Proxy)原理解析与配置总结
前端
怕浪猫37 分钟前
顶级模型一句话,AI 写出了能玩的 QQ飞车
前端·面试·github
huakoh38 分钟前
MCP 报错分不清?先看响应里是 result 还是 error
前端
呃呃呃呃ex38 分钟前
10. 现代前端工程化:ES6 React 项目实战与原理解析
前端·javascript