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函數