let path = require('path')
let fs = require('fs')
function Module(filename){ //构造函数
this.filename = filename;
this.exports = {}
}
//扩展名存在它的构造函数上,做为私有属性
Module._extentions = ['.js','.json','.node'] //若是没有后缀
Module._cache = {} //专门缓存路径
Module._resolvePathname = function(filename){ //获取绝对路径的
let p = path.resolve(__dirname,filename)
console.log(p)
}
function req(filename){ //filename是文件名, 文件名可能没有后缀
//因此咱们要弄一个绝对路径,缓存是根据路径来的
filename = Module._resolvePathname(filename)
}
let result = req('a') //req过来的是一个模块,因此须要一个构造函数
复制代码
这个代码的运行结果是e:\meterWang\ZF\require\a ;咱们还要给它加上后缀。有没有后缀用path.extname(p) 那么咱们就要把文件的后缀加上,并判断这个文件存不存在javascript
Module._resolvePathname = function(filename){ //获取绝对路径的
let p = path.resolve(__dirname,filename)
if(!path.extname(p)){
for(var i=0;i<Module._extentions.length;i++){
let newPath = p+Module._extentions[i];
try{ //accessSync若是文件不存在会报错
fs.accessSync(newPath)
return newPath
}catch(e){
}
}
}
return p
}
复制代码
路径拿到了,那要看看在缓存里有没有。Module._catch 那么方法来了java
function req(filename){ //filename是文件名, 文件名可能没有后缀
//因此咱们要弄一个绝对路径,缓存是根据路径来的
filename = Module._resolvePathname(filename);
let cacheModule = Module._cache[filename];
if(cacheModule){ //缓存里有直接把缓存的exports属性。
return cacheModule.exports
}
//没有就建立一个模块
let module = new Module(filename);
module.load(filename) //加载这个模块
}
复制代码
咱们加载这个模块用到了load方法,而且是实例上的,那么就要在Module的原型上加:node
Module.prototype.load =function(filename){
//模块有多是json,js
let ext = path.extname(filename).slice(1);
Module.__extentions[ext](this);
}
复制代码
Module.__extentionsext;这里的这段代码就是在__extentions这个数组上加了一个属性,属性值是一个方法,this表明的就是当前实例,其实就是至关于下面这个代码:json
Module.wrapper = [
"(function(exports,require,module,__dirname,__fikename){","\n})"
]
Module.wrap = function(script){
return Module.wrapper[0]+script+Module.wrapper[1]
}
Module.__extentions['js'] = function(module){
let script = fs.readFileSync(module.filename);
let fnStr = Module.wrap(script)
//第一个参数就是this指向,第二个参数就是module.exports
//vm.runInThisContext(fnStr)==>eval()执行没有意义,因此要给它call一下 vm.runInThisContext(fnStr).call(module.exports,module.exports,req,module)
}
复制代码
咱们之前说过,node价值模块实际上是在外层加了一个(function(exports,require,module,__dirname,__fikename){/**代码**/})这个壳,因此咱们本身写的时候也要加上。数组
如今咱们的require模块就写完了,完整的代码以下缓存
let path = require('path');
let fs = require('fs');
let vm= require('vm');
function Module(filename){
this.filename = filename;
this.exports = {};
this.loaded = false;
}
Module._cache = {}; //缓存
Module.__extentions = ['.js','.json','.node'] //后缀
Module._resolvePath = function(filename){
let p = path.resolve(__dirname,filename);
if(!path.extname(p)){//后缀没有的化就给它加上
for(var i=0;i<Module.__extentions.length;i++){
let newPath = p + Module.__extentions[i]
try{ //accessSync若是文件不存在会报错
fs.accessSync(newPath)
return newPath
}catch(e){
}
}
}
return p
}
Module.wrapper = [
"(function(exports,require,module,__dirname,__fikename){","\n})"
]
Module.wrap = function(script){
return Module.wrapper[0]+script+Module.wrapper[1]
}
Module.__extentions['js'] = function(module){
let script = fs.readFileSync(module.filename);
let fnStr = Module.wrap(script)
//第一个参数就是this指向,第二个参数就是module.exports
vm.runInThisContext(fnStr).call(module.exports,module.exports,req,module)
}
Module.prototype.load =function(filename){
//模块有多是json,js
let ext = path.extname(filename).slice(1);
Module.__extentions[ext](this);
}
function req(filename){
filename = Module._resolvePath(filename)
//路径有了就能够加载了
let cacheModule = Module._cache[filename]
if(cacheModule){
return cacheModule.exports
}
let module = new Module(filename)
module.load(filename);
Module._cache[filename] = module; //加入缓存
module.loaded = true; // 表示当前模块是否加载完
return module.exports;
}
let result = req('a');
console.log(result)
复制代码
a.js文件内容以下bash
console.log('加载');
module.exports = 'zufe'
复制代码
vscode执行结果以下:app
加载 zufe函数