这里有新鲜出炉的 Node.JS 入门教程,程序狗速度看过来!
Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台, 用来方便地搭建快速的 易于扩展的网络应用 · Node.js 借助事件驱动, 非阻塞 I/O 模型变得轻量和高效, 非常适合 运行在分布式设备 的 数据密集型 的实时应用
这是本系列的第三篇文章了,前面 2 篇网友们反馈回来不少的消息,加上最近 2 天比较忙,一直没来得及整理,周末了,赶紧给大家整理下发出来,本文讲的是 node.js 模块
简介及资料
通过 Node.js 的官方 API 可以看到 Node.js 本身提供了很多核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,可以 require('模块名') 去获取;核心模块具有最高的加载优先级(有模块与核心模块同名时会体现)
(本次主要说自定义模块)
Node.js 还有一类模块为文件模块,可以是 JavaScript 代码文件(.js 作为文件后缀)、也可以是 JSON 格式文本文件(.json 作为文件后缀)、还可以是编辑过的 C/C++ 文件(.node 作为文件后缀);
文件模块访问方式通过 require('/ 文件名. 后缀') require('./ 文件名. 后缀') requrie('../ 文件名. 后缀') 去访问,文件后缀可以省略;以 "/" 开头是以绝对路径去加载,以 "./" 开头和以 "../" 开头表示以相对路径加载,而以 "./" 开头表示同级目录下文件,
前面提到文件后缀可以省略,Nodejs 尝试加载的优先级 js 文件 > json 文件 > node 文件
创建一个自定义模块
以一个计数器为例
- var outputVal = 0; //输出值
- var increment = 1; //增量
- /* 设置输出值 */
- function seOutputVal (val) {
- outputVal = val;
- }
- /* 设置增量 */
- function setIncrement(incrementVal){
- increment = incrementVal;
- }
- /* 输出 */
- function printNextCount()
- {
- outputVal += increment;
- console.log(outputVal) ;
- }
- function printOutputVal() {
- console.log(outputVal);
- }
- exports.seOutputVal = seOutputVal;
- exports.setIncrement = setIncrement;
- module.exports.printNextCount = printNextCount;
- 自定义模块 示例源码
示例中重点在于 exports 和 module.exports; 提供了外部访问的接口,下面调用一下看看效果吧
调用自定义模块
- /*
- 一个Node.js文件就是一个模块,这个文件可能是Javascript代码、JSON或者编译过的C/C++扩展。
- 重要的两个对象:
- require是从外部获取模块
- exports是把模块接口公开
- */
- var counter = require('./1_modules_custom_counter');
- console.log('第一次调用模块[1_modules_custom_counter]');
- counter.seOutputVal(10); //设置从10开始计数
- counter.setIncrement (10); //设置增量为10
- counter.printNextCount();
- counter.printNextCount();
- counter.printNextCount();
- counter.printNextCount();
- /*
- require多次调用同一模块不会重复加载
- */
- var counter = require('./1_modules_custom_counter');
- console.log('第二次调用模块[1_modules_custom_counter]');
- counter.printNextCount();
- 自定义模式调用 源码
运行可以发现通过 exports 和 module.exports 对外公开的方法都可以访问!
示例中可以看到,我两次通过 require('./1_modules_custom_counter') 获取模块,但是第二次引用后调用 printNextCount() 方法确从 60 开始~~~
原因是 node.js 通过 requirerequire 多次调用同一模块不会重复加载,Node.js 会根据文件名缓存所有加载过的文件模块,所以不会重新加载了
注意:通过文件名缓存是指实际文件名,并不会因为传入的路径形式不一样而认会是不同的文件
在我创建的 1_modules_custom_counter 文件中有一个 printOutputVal() 方法,它并没有通过 exports 或 module.exports 提供对外公开访问方法,
如果 1_modules_load 文件中直接访问运行会出现什么样的情况呢?
答案是:TypeError: Object #<Object> has no method 'printOutputVal'
exports 和 module.exports 区别
经过上面的例子,通过 exports 和 module.exports 对外公开的方法都可以访问!那既然两种都能达到效果,但总得有点区别的吧~~~ 用个例子看看吧!
- var counter = 0;
- exports.printNextCount = function (){
- counter += 2;
- console.log(counter);
- }
- var isEq = (exports === module.exports);
- console.log(isEq);
- 2_modules_diff_exports.js 文件源码
下面再新建个 2_modules_diff_exports_load.js 文件调用一下
- var Counter = require('./2_modules_diff_exports');
- Counter.printNextCount();
调用后,执行结果如上图
我在 2_modules_diff_exports_load.js 文件中输出了 isEq 的值 (var isEq = (exports === module.exports); ), 返回的 true
PS: 注意是三个等号,如果不清楚自已查查资料吧!
不用急着下结论,把这两个 JS 文件分别改成 module.exports 对应的代码
- //修改后的2_modules_diff_exports.js源码如下
- var counter = 0;
- module.exports = function(){
- counter += 10;
- this.printNextCount = function()
- {
- console.log(counter);
- }
- }
- var isEq = (exports === module.exports);
- console.log(isEq);
- //修改后的2_modules_diff_exports_load.js文件源码如下
- var Counter = require('./2_modules_diff_exports');
- var counterObj = new Counter();
- counterObj.printNextCount();
调用后,执行结果如上图
我在 2_modules_diff_exports_load.js 文件中输出了 isEq 的值 (var isEq = (exports === module.exports); ), 返回的 false,这与用先前得到的结果不一致!
PS:不要用 Counter.printNextCount(); 去访问,你只会得到一个错误的提示
API 提供了解释
http://nodejs.org/api/modules.html
Note that exports is a reference to module.exports making it suitable for augmentation only. If you are exporting a single item such as a constructor you will want to use module.exports directly instead exports 仅仅是 module.exports 的一个地址引用。nodejs 只会导出 module.exports 的指向,如果 exports 指向变了,那就仅仅是 exports 不在指向 module.exports,于是不会再被导出
参考其它理解:
http://www.hacksparrow.com/node-js-exports-vs-module-exports.html
http://zihua.li/2012/03/use-module-exports-or-exports-in-node/
module.exports 才是真正的接口,exports 只不过是它的一个辅助工具。最终返回给调用的是 module.exports 而不是 exports。 所有的 exports 收集到的属性和方法,都赋值给了 Module.exports。当然,这有个前提,就是 module.exports 本身不具备任何属性和方法。 如果,module.exports 已经具备一些属性和方法,那么 exports 收集来的信息将被忽略。
exports 和 module.exports 覆盖
上面也也基本明白了 exports 和 module.exports 的关系和区别,但如果同时针对 printNextCount() 方法存在 exports 和 module.exports,结果如何?
调用结果
从结果可以看出,并没有报错,表示可以这么定义,但最终 module.exports 覆盖了 exports
虽然结果不会报错,如果这么用开发中难免会有一些问题存在,所以
1. 最好别分别定义 module.exports 和 exports
2.NodeJs 开发者建议导出对象用 module.exports, 导出多个方法和变量用 exports
其它...
API 中还提供了其它的方法,就不细讲了,在上面例子的基础上自已动手一输出就知道了
module.id
返回 string 类型的模块标识,一般为完全解析后的文件名
module.filename
返回一个 string 类型的完全解析后文件名
module.loaded
返回一个 bool 类型,表示是否加载完成
module.parent
返回引用该模块的模块
module.children
返回该模块引用的所有模块对象的数组
来源: http://www.phperz.com/article/17/0502/275836.html