CommonJs

require的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 __dirname = getDirname(__filename)
//用call改变模块里的this指向,初始this===exports===module.exports
__require.call(exports, exports, require, module, __filename, __dirname)
//5. 缓存module.exports
cache[moduleId] = module.exports
//6. 返回module.exports
return module.exports
}

总结:

  • 模块在函数环境里
    • 变量在函数作用域,不共享
    • var声明的变量挂载在函数
    • 不用var或let或const声明的变量挂载在global上
  • 一开始模块里,this===exports===module.exports
  • 模块最终导出的始终是module.exports
  • global在一个node.js环境中共享

举个例子

1
2
3
4
5
6
7
8
9
10
11
this.a = 1;
exports.b = 2;
exports = {c:3}
module.exports = {d:4}
exports.e = 5
this.f = 6
/*
this: {a:1, b:2, f:6}
exports: {c:3, e:5}
module.exports: {d:4}
*/