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。(从函数可以见得)。
