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); // trueconsole.log(this === module.exports); // trueconsole.log(module.exports === exports); // truemodule.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 }