node基础(2.1)-----手写一个require模块

本文详细介绍了如何从零开始实现Node.js的require机制。包括解析文件路径、处理文件扩展名、读取文件内容、执行文件并缓存结果等核心步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动手写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)
那么我们就要把文件的后缀加上,并判断这个文件存不存在

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
那么方法来了

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的原型上加:

Module.prototype.load =function(filename){
    //模块有可能是json,js
    let ext = path.extname(filename).slice(1);
    Module.__extentions[ext](this);
}

Module.__extentionsext;这里的这段代码就是在__extentions这个数组上加了一个属性,属性值是一个方法,this代表的就是当前实例,其实就是相当于下面这个代码:

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文件内容如下

console.log('加载');
module.exports = 'zufe'

vscode执行结果如下:

加载
zufe

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值