共计 2502 个字符,预计需要花费 7 分钟才能阅读完成。
node 源码
const path = require("path");
const fs = require("fs");
const vm = require("vm");
function Module(id) {
this.id = id;
this.exports = {};}
Module.wrap = function (script) {
let arr = ["(function (exports, require, module, __filename, __dirname){",
script,
"})",
];
return arr.join("");
};
Module._extensions = {".js": function (module) {let content = fs.readFileSync(module.id, "utf8");
let fnStr = Module.wrap(content);
let fn = vm.runInThisContext(fnStr);
let exports = module.exports;
let require = myRequire;
let __filename = module.id;
let __dirname = path.dirname(module.id);
// 这里的 this 就是 exports 对象
fn.call(exports,exports, require, module, __filename, __dirname);
// 用户会给 exports 赋值
// console.log(fn.toString());
},
".json": function (module) {let content = fs.readFileSync(module.id);
module.exports = JSON.parse(content);
},
};
Module._resolveFilename = function (filepath) {let filePath = path.resolve(__dirname, filepath);
let exists = fs.existsSync(filePath);
if (exists) return filePath;
// 尝试增加后缀
let keys = Object.keys(Module._extensions);
for (let i = 0; i < keys.length; i++) {let curentPath = filePath + keys[i];
if (fs.existsSync(curentPath)) {return curentPath;}
}
};
Module.prototype.load = function (filename) {
// 获取文件的后缀进行加载
let extname = path.extname(filename);
Module._extensions[extname](this); // 依据对应的后缀名进行加载
};
Module._load = function (filepath) {
// 将门路转化成绝对路径
let filename = Module._resolveFilename(filepath);
let module = new Module(filename);
module.load(filename);
return module.exports;
};
function myRequire(filepath) {
// 依据门路加载这个模块
return Module._load(filepath);
}
exports/module.exports/this 的关系
fn.call(exports,exports, require, module, __filename, __dirname);
从代码中咱们能够看到 this 就是 exports。
a.js 文件代码
console.log(this === exports); // true
console.log(this === module.exports); // true
console.log(module.exports === exports); // true
module.exports = 1;
use.js 文件
let r = require("./a"); // 同步语法
console.log(r);
从下面的代码咱们能够确认 this === exports === module.exports
exports 和 module.exports 输入后果为什么不一样
既然 this === exports === module.exports
,为什么在 a.js 文件中上面的代码获取后果不一样呢?
exports = 1; // 如果应用 exports = 1, 获取的时候失去的是值是 {}
module.exports = 1; // 获取的值是 1
看上面代码,思考为什么这样
let a = b = {}
a = 1;
console.log(b); // 输入后果是 {},而不是 1
let a = b = {}
a = 'hello';
console.log(b);// 输入后果是 {},而不是 1
let a = b = {}
a = {name:'fung', age:3};
console.log(b); // 输入后果是 {},而不是 1
let a = b = {}
a.name = 'a';
a.age = 3;
console.log(b); // 输入后果是 {name: 'a', age: 3},而不是 {}
下面三个代码例子就能够阐明为什么 exports 和 module.exports 输入后果不一样。
开始的时候
let exports = module.exports = {}
fn.call(exports,exports, require, module, __filename, __dirname);
return module.exports
开始 exports module.exports this 都指向同一个援用地址,当咱们给 exports 赋值的时候,则断开了 exports 的指向,并不会扭转 module.exports 和 this 的指向问题。
然而上面代码的输入后果则是一样的
module.exports.a = 1 // 输入 {a: 1}
exports.a = 1 // 输入 {a: 1}
this.a = 1 // 输入 {a: 1}
正文完
发表至: javascript
2020-08-04