nodejs导出模块功能原理的个人理解
2016-03-17 00:00
495 查看
摘要: nodejs导出模块功能原理的个人理解
假设我们创建了一个模块foo.js,内容如下(这个模块的功能只是的导出一个简单对象):
一般会这样使用这个模块:
我们给require()传入一了个模块文件,然后就从返回值中得到了文件中导出的对象。nodejs内部的处理原理大概可以简单描述
1.声明一个模块加载构造函数,它至少包括一个名为exports的属性,值为一个空对象:
2.如果是初次加载js模块文件,在node定位到具体js文件后,就先创建一个Module的实例:
3.node通过内置fs模块同步读取文件(这里读取文件时必然会导致I/O阻塞):
4.读取完成后,node会对读取的文件内容进行头尾包装(wrapper)。大概就是通过字符串拼接,把读取到的文件代码都包装到一个匿名函数中:
5.把包装的代码传入一个类似eval的函数执行,返回一个匿名的function对象,原来foo.js文件中的代码都被写到了这个function中,作用域就自然被封装隔离起来了,这时它就是一个真正意义的模块了:
6.把moduleP对象的exports属性和moduleP对象本身作为参数传入上一步创建的function执行,这时在第四步的包装过程中给匿名函数最后加入的代码 "return module.exports;"就发挥出模块导出的作用了:
当然,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对应的对象会被导出。
假设我们创建了一个模块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对应的对象会被导出。
相关文章推荐
- 使用ruby部署工具mina快速部署nodejs应用教程
- Google官方支持的NodeJS访问API,提供后台登录授权
- 浅谈Nodejs观察者模式
- nodejs教程之环境安装及运行
- nodejs中的fiber(纤程)库详解
- 基于NodeJS的前后端分离的思考与实践(五)多终端适配
- 基于NodeJS的前后端分离的思考与实践(二)模版探索
- 实例详解Nodejs 保存 payload 发送过来的文件
- 我的NodeJs学习小结(一)
- nodejs中实现sleep功能实例
- Nodejs异步回调的优雅处理方法
- Windows系统下使用Sublime搭建nodejs环境
- nodejs实现获取某宝商品分类
- nodejs简单实现中英文翻译
- Node.js插件的正确编写方式
- 使用upstart把nodejs应用封装为系统服务实例
- NodeJS Web应用监听sock文件实例
- Nodejs学习笔记之测试驱动
- Nodejs学习笔记之Stream模块
- 如何正确使用Nodejs 的 c++ module 链接到 OpenSSL