node基礎(2.1)-----手寫一個require模塊

動手寫require的思路

思路出來就開始寫代碼了,先寫個架子

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

相關文章
相關標籤/搜索