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

相关文章
相关标签/搜索