带着下面的问题去读读代码吧!javascript
node
里面的文件就是模块?js
文件,是如何执行的?exports
module.exports
的关系?js
里面的对象之间的引用关系?在node
里面,js
代码在被引入过去都会被包装成以下的函数,是否是咱们只须要再咱们的require
函数里面去调用这个函数(固然下面的那个函数须要咱们本身读取到文件内容,而后组装成下面的函数形式),解析函数字符串为可执行的js,传入引用的参数。module.exports
就会被赋值。再返回module.exports
,就获得了须要的模块里面的内容了前端
// (function(exports,module,require){ this == module.exports // true module.exports = 'hello'; // })
module.exports
与 exports
exports = module.exports exports.a = 'xxx' // 一个引用地址,module.exports也会被赋值 exports = 'xxx' // 这个时候exports的引用地址就错误了。就获取不到模块的内容了
但咱们传递给函数的参数是一个引用类型数据的时候。当函数执行的时候,会先执行参数赋值的阶段,引用类型数据的话,赋值的就是一个引用地址。就会出现以下的状况java
var test = {} function fn(a){ a.name = 'xxx' } fn(test) console.log(test) // {name:'xxx'}
const fs = require("fs"); const path = require("path"); const vm = require("vm"); function Module(filePath) { this.id = filePath; this.exports = {}; } Module._cache = {}; Module.fnStr = ["(function(module,exports,req,__fileName,__dirname){\n", "})"]; Module.extensions = { ".js": function(module) { const content = fs.readFileSync(module.id, "utf8"); const fnString = Module.fnStr[0] + content + Module.fnStr[1]; const fn = vm.runInThisContext(fnString); // 文件就是模块 exports = module.exports exports其实就是指向的 module.exports // 函数执行后 会给传递进去的module.exports赋值。module又是一个对象,函数参数的引用,就给下面实例化的 module上赋值了。就可以获取到文件的内容了 fn.call( module.exports, module, module.exports, req, module.id, path.dirname(module.id) ); }, ".json": function(module) { const jsonString = fs.readFileSync(module.id, "utf8"); module.exports = JSON.parse(jsonString); } }; Module.resolveFileName = function(filePath) { let absolutePath = path.resolve(__dirname, filePath); let flag = fs.existsSync(absolutePath); // 判断文件是否存在 let current = absolutePath; if (!flag) { let keys = Object.keys(Module.extensions); for (let i = 0; i < keys.length; i++) { let combinePath = absolutePath + keys[i]; let flag = fs.existsSync(combinePath); // 增长文件后缀后再判断文件是否存在 if (flag) { current = combinePath; break; } else { current = null; } } } if (!current) { throw new Error(`当前文件不存在${current}`); } return current; }; Module.prototype.load = function() { // this.id 就是文件路径 let extName = path.extname(this.id); Module.extensions[extName](this); }; function req(filePath) { let absolutePath = Module.resolveFileName(filePath); // 获取到文件的绝对路径 支持了 动态匹配.js .json后缀 let module = new Module(absolutePath); if (Module._cache[absolutePath]) { return Module._cache[absolutePath].exports; } // 值是一个引用地址。真正有值的时候是再执行完module.load()后 Module._cache[absolutePath] = module; module.load(); // 读取文件 return module.exports; }
本人前端菜鸟一枚,欢迎阅读并指出错误!