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 }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。