文档章节

nodejs导出模块功能原理的个人理解

码上有春天
 码上有春天
发布于 2016/03/17 17:34
字数 737
阅读 411
收藏 3

假设我们创建了一个模块foo.js,内容如下(这个模块的功能只是的导出一个简单对象):

var obj = {name: 'bar'};
module.exports = obj;

一般会这样使用这个模块:

var foo = require('./foo.js');
console.log(foo.name);/*输出 bar*/

我们给require()传入一了个模块文件,然后就从返回值中得到了文件中导出的对象。nodejs内部的处理原理大概可以简单描述

1.声明一个模块加载构造函数,它至少包括一个名为exports的属性,值为一个空对象:

function ModuleP(){
this.exports = {};
...
}

2.如果是初次加载js模块文件,在node定位到具体js文件后,就先创建一个Module的实例:

var moduleP = new ModuleP;

3.node通过内置fs模块同步读取文件(这里读取文件时必然会导致I/O阻塞):

var fs = require('fs');
var foo_js = fs.readFileSync('./foo.js');

4.读取完成后,node会对读取的文件内容进行头尾包装(wrapper)。大概就是通过字符串拼接,把读取到的文件代码都包装到一个匿名函数中:

var packStr = '(function(exports, module){'+ foo_js + ' return module.exports;})';
/*这时它只是一个字符串*/

5.把包装的代码传入一个类似eval的函数执行,返回一个匿名的function对象,原来foo.js文件中的代码都被写到了这个function中,作用域就自然被封装隔离起来了,这时它就是一个真正意义的模块了:

var packObj = eval(packStr);
/*通过eval函数,把wrapper后的字符串变成了一个匿名函数,并返回、赋值给变量packObj*/

6.把moduleP对象的exports属性和moduleP对象本身作为参数传入上一步创建的function执行,这时在第四步的包装过程中给匿名函数最后加入的代码 "return module.exports;"就发挥出模块导出的作用了:

var foo = packObj(moduleP.exports, moduleP);
/*这里就得到了从模块中导出的变量*/


当然,node的具体实现肯定比这个要复杂的多,会考虑到模块路径查找、模块缓存、文件读取时去掉bom信息等等。

但从这里可以知道这么几点:

1.模块文件中的代码被node加载完会立即被处理一次,封装成模块后执行。

2.node模块文件中之所以能用直接使用exports、module这两个对象,是因为它们其实是通过参数传递过来的,都是形参名。exports的实参是moduleP.exports,module的实参是moduleP。exports和module.exports一开始都是指向同一个空对象。

3.最后返回的是module.exports,所以如果在模块文件(foo.js)中把exports或module.exports中的任意一个赋值为一个对象,它俩之间就没任何关系了,只有module.exports对应的对象会被导出。


© 著作权归作者所有

码上有春天
粉丝 5
博文 82
码字总数 55985
作品 0
广州
程序员
私信 提问
require时,exports和module.exports的区别你真的懂吗?

面试会问 require 的运行机制和缓存策略你了解吗? require 加载模块的是同步还是异步?谈谈你的理解 exports 和 module.exports 的区别是什么? require 加载模块的时候加载的究竟是什么? ...

大西轰已在服务区
08/20
0
0
求份 深圳 前端开发 工作

简  历 基本信息 姓 名:刘昭辉 性 别:男 出生日期:1989年12月24日 联系电话:134 8079 1024 电子信箱:hi.liuzhaoxin#gmail.com 工作年限:三年以上 技术专长 1.熟练掌握HTML、CSS、A...

liuzhaohui
2012/12/05
691
11
Node.js---01、初识NodeJS和Node.js的HTTP服务器搭建

一、前言 我们先从以下几个方面在大体上认识一下Node.js: Node.js 是什么?==> 运行环境 是一个 可以运行 并加载 ES语法的 脚本运行环境 JS(ES5)、ES6、Common.js 语法 …… Node.js 可以加...

秋季长青
2017/11/06
193
0
[深圳] 求份 前端开发 工作

简  历 基本信息 姓 名:刘昭辉 性 别:男 学 历:中专 出生日期:1989年12月24日 联系电话:134 8079 1024 电子信箱:hi.liuzhaoxin#gmail.com 工作年限:三年以上 技术专长 1.熟练掌握H...

liuzhaoxin
2012/10/18
381
3
结合源码分析 Node.js 模块加载与运行原理

Node.js 的出现,让 JavaScript 脱离了浏览器的束缚,进入了广阔的服务端开发领域。而 Node.js 对 CommonJS 模块化规范的引入,则更是让 JavaScript成为了一门真正能够适应大型工程的语言。 ...

技术小能手
2018/08/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis Plus删除

/** @author beth @data 2019-10-17 00:30 */ @RunWith(SpringRunner.class) @SpringBootTest public class DeleteTest { @Autowired private UserInfoMapper userInfoMapper; /** 根据id删除......

一个yuanbeth
今天
4
0
总结

一、设计模式 简单工厂:一个简单而且比较杂的工厂,可以创建任何对象给你 复杂工厂:先创建一种基础类型的工厂接口,然后各自集成实现这个接口,但是每个工厂都是这个基础类的扩展分类,spr...

BobwithB
今天
5
0
java内存模型

前言 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模...

ls_cherish
今天
4
0
友元函数强制转换

友元函数强制转换 p522

天王盖地虎626
昨天
5
0
js中实现页面跳转(返回前一页、后一页)

本文转载于:专业的前端网站➸js中实现页面跳转(返回前一页、后一页) 一:JS 重载页面,本地刷新,返回上一页 复制代码代码如下: <a href="javascript:history.go(-1)">返回上一页</a> <a h...

前端老手
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部