nodejs中的模块的理解

nodejs所谓的模块就是一个文件,或者是匿名函数。(CommonJs)
require
exports
module.exports。

为什么直接console.log(typeof require('*****')) # 是一个string类型?

但是使用的话,又是一个对象函数?

https://github.com/nodejs/node/blob/v5.x/lib/internal/bootstrap_node.js
https://github.com/nodejs/node/blob/v5.x/lib/module.js 
复制代码
https://github.com/nodejs/node/blob/v5.x/lib/module.js

通过对源码的查看:

364行列:

Module.prototype.require = function(path) {

  assert(path, 'missing path');

  assert(typeof path === 'string', 'path must be a string');

  return Module._load(path, this, /* isMain */ false);

};

复制代码
Module._load = function(request, parent, isMain) {

  if (parent) {
    debug('Module._load REQUEST %s parent: %s', request, parent.id);
  }

  var filename = Module._resolveFilename(request, parent);
复制代码
# module._compile:

Module.prototype._compile = function(content, filename) {
 var self = this;
 var args = [self.exports, require, self, filename, dirname];
 return compiledWrapper.apply(self.exports, args);
};

复制代码

得出以下结论

require 一个文件的时候,会对其进行进行一个匿名函数的包装。

(function (exports, require, module, __filename, __dirname) {
  // 模块源码
});
复制代码

requier顺序:

1、先从缓存中读取,如果没有则继续往下
2、判断需要模块路径是否以/结尾,如果不是,则要判断
    a. 检查是否是一个文件,如果是,则转换为真实路径
    b. 否则如果是一个目录,则调用tryPackage方法读取该目录下的package.json文件,把里面的main属性设置为filename
    c. 如果没有读到路径上的文件,则通过tryExtensions尝试在该路径后依次加上.js,.json和.node后缀,判断是否存在,若存在则返回加上后缀后的路径
3、如果依然不存在,则同样调用tryPackage方法读取该目录下的package.json文件,把里面的main属性设置为filename
4、如果依然不存在,则尝试在该路径后依次加上index.js,index.json和index.node,判断是否存在,若存在则返回拼接后的路径。
5、若解析成功,则把解析得到的文件名cache起来,下次require就不用再次解析了,否则若解析失败,则返回false
复制代码

exports和module.exports的区别

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    function someFunc() {}
    exports = someFunc;
    module.exports = someFunc;
  })(module, module.exports);
  return module.exports;
}
复制代码
exports = module.exports,所以说,一开始这两个东西指向同一个对象实例
exports.x = function() {  
//在exports上添加了一个方法,module.exports也添加了同样的方法,因为它们指向了同样的对象实例  
    console.log("Hi!");  
}  
module.exports.x();
复制代码

总结

# exports其实是module的属性,require则是Module原型的方法。exports.xx=xx,其实跟module.exports.xx=xx其实是一样的,不过如果直接为export赋值,则不能写成exports=xx,而应该写成module.exports=xx,因为exports在这里只是一个引用。

# 从上面也可以看到,每一次require,都会把new一个Module,并且把这个Module添加到当前模块的children中,并且返回新建的Module对象的exports。

# 其实node启动的原理跟require是一样的,src/node.cc中的node::LoadEnvironment函数会被调用,在该函数内则会接着调用lib/internal/bootstrap_node.js中的代码,并执行startup函数,startup函数会执行Module.runMain方法,而Module.runMain方法会执行Module._load方法,参数就是命令行的第一个参数(比如: node ./app.js),如此,跟上面require就走到一起了。
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值