node乞丐版require方法

在node环境中,每一个文件都是一个模块,解决了命名冲突的问题,node会默认给js加上一个函数,比如一个js文件打印this:

console.log(this);//{}

并不是像浏览器一样,this是window(node没有window,只有global),而是一个空对象,再打印arguments:

  '0': {},

  '1': { [Function: require]

  '2':Module 

  '3': 'E:\\mydata\\project\\bootstrap\\html\\coding\\nodenodule\\a.js',

  '4': 'E:\\mydata\\project\\bootstrap\\html\\coding\\nodenodule' 

内容有点多,可以自行打印看看,但是可以看到,是五个参数,通过一个大佬的对node的调试和过程分析,确定require方法引入的时候相当于一个自执行函数:

(function (exports, require, module, __filename, __dirname) {

})

且我们可以实现一个简易的require方法:

1、_resolveFilename处理路径,判断存在和转换成绝对路径

2、创建module实例new Module

3、调用实例方法load加载文件

4、通过_extensions处理不同文件

5、给文件加一个函数并自执行

6、处理多次调用

7、返回module.exports

直接上代码:

const fs = require('fs');

const path = require('path');

const vm = require('vm');//虚拟机,可以到node官网文档了解



//自定义的require方法

function myrequire(filename) {

 //处理路径

 filename = Module._resolveFilename(filename);

 //判断是否有缓存

 if(Module._cache[filename]){

  return Module._cache[filename].exports;

 }

 //初始化实例

 let module = new Module(filename);

 //进行加载

 module.load();

 Module._cache[filename] = module;

 //返回内容

 return module.exports;

}

//缓存

Module._cache = {}

//构造函数,主要内容id(也就是路径做为id)和一个空对象

function Module(id) {

 this.id = id;

 this.exports = exports;

}

//处理路径方法

Module._resolveFilename = function (filename) {

 //生成绝对路径

 let absPath = path.resolve(__dirname, filename);

 //fs方法,判断是否存在文件

 if(fs.existsSync(absPath)){

  return absPath;

 }else{

  //引入有可能是require('./a'),没有后缀,手动拼接上判断

  let keys = Object.keys(Module._extensions);

  for(let i = 0; i< keys.length; i++){

   let path = absPath + keys[i];

   if(fs.existsSync(path)){

    //不加后缀,寻找到第一个直接返回,如果同名不同后缀不往下走

    return path;

   }

  };

  //如果都没有直接报错不存在

  throw new Error('module is not exist');

 }

}

//不同文件处理方法

Module._extensions = {

 '.js'(module){

  //同步读取文件

  let content = fs.readFileSync(module.id, 'utf8');

  //构造成一个函数

  content = Module.wrapper[0] + content + Module.wrapper[1];

  //使用runInThisContext变成不依赖上下文环境方法

  let fn = vm.runInThisContext(content);

  let exports = module.exports;

  let dirname = path.dirname(module.id);

  //调用方法,改变this

  fn.call(exports, exports, myrequire, module, module.id, dirname);

 },

 '.json'(module){

  //直接可以返回

  let content = fs.readFileSync(module.id, 'utf8');

  module.exports = content;

 }

}

//js内容包裹成一个函数使用

Module.wrapper = [

 '(function(exports, require, module, __firname, __dirname){',

 '})'

]

//加载方法

Module.prototype.load = function () {

 //获取后缀,调用不同后缀方法

 let extname = path.extname(this.id);

 Module._extensions[extname](this);

}



let a = myrequire('./a');

let j = myrequire('./j');

console.log(a);

console.log(j);

node的方法上千行,我这只是学习一下大概原理,可以拷贝代码运行,然后理解理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值