一、前言
Commonjs 是nodejs 提出的默认的模块化解决方案:每个文件就是一个模块,文件的最顶层就处于一个函数作用域中,函数接受了一些参数(五个),这五个参数在模块中可见。在函数作用域(文件作用做)中定义的变量、 函数、类,都是私有的,对其他文件不可见。
二、分析commonjs 的导出
代码如下:
this.a = 1;
exports.b = 2;
exports = {
c:3,
}
modules.exports = {
d:4,
}
this.e = 5;
exports.f = 6;
modules.exports.e = 7;
请问,以上代码的导出结果是啥?
我们知道,一个模块的导入,依赖的是require函数, 就像这样: const module1 = require('./module1.js') , 要从原理上解释清楚以上模块的导出结果,就需要分析require函数执行的时候都干了些啥???
下面给出require 函数的伪代码实现。
三、Require 函数的原理(伪代码)
先看代码再解释:
// 不是重点省略实现
function getModuleId(path){}
// 不是重点省略实现
function getDirname(path){}
// 缓存
var cache = {}
function require (path){
// 1. 根据传递的模块路径找到对应的绝对路径,作为模块的id
var moduleId = getModuleId(path)
// 2. 判断是否是第一次执行(是否有缓存),如果有缓存,直接返回缓存,没有缓存就执行一个函数得到结果,然后把结果缓存并导出
if(!!cache[moduleId]){
return cache[moduleId]
}
// 3. require真正需要运行的函数。
function _require(exports,require,module,__filename,__dirname){
// 通过前面的的id, 获取模块的代码,放在这里,等待调用
// 因此,commonjs 模块的全局上下文处于一个函数环境,函数接收五个参数,这也是为什么commonjs 全局环境具有五个参数的原因。
/* 假设这里已经根据path的绝对路劲拿到了 module1.js 的代码,就会放在这里
* this.a = 1;
* module.exports = {
* b:2
* }
* console.log(__filename)
* console.log(__dirname)
* console.log(arguments.length)
*
* // 等等,就是一个普通的函数。。。。
* */
}
// 准备_require函数需要的参数
var module = {
exports:{}
}
var exports = module.exports;
// 文件的绝对路径
var __filename = moduleId
// 文件所在目录的绝对路径
var __dirname = getDirname(__filename);
// 执行_require 函数,给模块赋值,使用call 绑定函数中的this 为exports
_require.call(exports,exports,require,module,__filename,__dirname);
// 缓存module
cache[moduleId] = exports;
// 返回赋值好的模块对象
return module.exports;
}
三、解释require函数
require(path) 主要做了以下几件事:
- 根据传进来的饿
path获取到文件的绝对路径作为模块id,记为moduleId - 根据
moduleId判断是否有缓存,有缓存就返回,没有继续执行下面的饿步骤。 - 准备一个辅助函数
_require(exports,require,module,__filename,__dirname),根据moduleId 获取到模块定义的代码,然后把它放在这个函数体中。 - 准备好需要的五个参数。
exports,module,__filename,__dirname。var module = { exports:{} } var exports = module.exports; // 文件的绝对路径 var __filename = moduleId // 文件所在目录的绝对路径 var __dirname = getDirname(__filename);可以看到 expoorts 就指向 module.exports,他们是同一片内存空间。
- 通过
FUnction.prototype.call调用该函数,可以将将函数的this绑定到exports,函数执行过程中会给module.exports 赋值。因此 this、exports、module.exports指向同一片内存空间。
- 缓存exports.
- 返回exports.
四、回答前面的问题(分析commonjs 的导出)
exports = {
d:4,
e:7,
f:6
}
认真看了前面这里肯定不用解释。
码字不易,帮到你就给个赞吧