假设我们有两个模块, 分别为index.js和a.js, 代码如下:
// 模块a
console.log("module a");
module.exports = "a";
另有index模块引入了模块a
console.log("index module");
var a = require("./a");
console.log(a);
在node环境中, 每个文件代表一个模块, 那么它是如何确保每个模块的变量不互相污染呢? 在node环境中, 每个模块内部的代码, 都被放入了一个函数环境内, 模块代码中所使用的的module
, require
, exports
等都是这个函数的参数, 正因如此, 我们才能够在模块代码中直接使用require函数和module对象.
那么合并后的模块的代码就相当于
(function (modules) {
// 提供require函数等
// 执行入口模块
require("./src/index.js");
})({
"./src/a.js": function (module, exports, require) {
console.log("module a");
module.exports = "a";
},
"./src/index.js": function (module, exports, require) {
console.log("index module");
var a = require("../src/a.js");
console.log(a);
}
});
每一个模块的路径, 作为唯一标识, 可以确定一个模块. 这个模块放入一个函数中. require的模块也使用统一的路径格式. 这个立即执行函数里面, 就需要提供模块代码需要的require函数, module和exports对象. 并且立即执行函数里面, 一定会执行入口模块.
由于commonjs模块化标准会对模块进行缓存, require函数的作用, 就是查看某个模块是否曾经被加载过, 如果是, 则直接返回该模块的导出结果, 如果不是, 则运行该模块, 并且返回该模块导出的结果, 并且将该模块缓存. 那么这个立即执行函数中, 就需要有一个对象, 保存所有的缓存模块.
代码如下
(function (modules) {
// 提供require函数等
var installedModules = {
"./src/a.js": {
i: "./src/a.js", // 模块id
l: false, // 是否完成导入
exports: "a" // 模块的导出内容
}
};
function require(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId, // 模块id
l: false, // 是否完成导入
exports: {} // 模块的导出内容
};
modules[moduleId].call(module.exports, module, module.exports, require);
module.l = true; // 此时完成载入, 设置l为true
return module.exports;
}
// 执行入口模块
require("./src/index.js");
})({
"./src/a.js": function (module, exports, require) {
console.log("module a");
module.exports = "a";
},
"./src/index.js": function (module, exports, require) {
console.log("index module");
var a = require("../src/a.js");
console.log(a);
}
});
网友评论