zl程序教程

您现在的位置是:首页 >  后端

当前栏目

跟我学Nodejs(三)---Node.js模块

NodejsJSNode模块 --- 跟我学
2023-06-13 09:15:27 时间

简介及资料

   通过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文件

创建一个自定义模块

   以一个计数器为例

复制代码代码如下:


varoutputVal =0;    //输出值
varincrement=1;   //增量
/*设置输出值*/
functionseOutputVal(val){
   outputVal=val;
}
/*设置增量*/
functionsetIncrement(incrementVal){
   increment=incrementVal;
}
/*输出*/
functionprintNextCount()
{   
   outputVal+=increment;
   console.log(outputVal);
}
functionprintOutputVal(){
   console.log(outputVal);
}
exports.seOutputVal=seOutputVal;
exports.setIncrement=setIncrement;
module.exports.printNextCount=printNextCount;
自定义模块示例源码

示例中重点在于exports和module.exports;提供了外部访问的接口,下面调用一下看看效果吧

调用自定义模块

复制代码代码如下:


/*
   一个Node.js文件就是一个模块,这个文件可能是Javascript代码、JSON或者编译过的C/C++扩展。
   重要的两个对象:
   require是从外部获取模块
   exports是把模块接口公开   
*/
varcounter=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多次调用同一模块不会重复加载
*/
varcounter=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>hasnomethod"printOutputVal"

exports和module.exports区别

经过上面的例子,通过exports和module.exports对外公开的方法都可以访问!那既然两种都能达到效果,但总得有点区别的吧~~~用个例子看看吧!

复制代码代码如下:
varcounter =0;    
exports.printNextCount=function(){   
   counter+=2;
   console.log(counter);
}
varisEq=(exports===module.exports);
console.log(isEq);
2_modules_diff_exports.js文件源码

下面再新建个2_modules_diff_exports_load.js文件调用一下

复制代码代码如下:
varCounter=require("./2_modules_diff_exports");
Counter.printNextCount();

   调用后,执行结果如上图

   我在2_modules_diff_exports_load.js文件中输出了isEq的值 (varisEq=(exports===module.exports);),返回的true

   PS:注意是三个等号,如果不清楚自已查查资料吧!

不用急着下结论,把这两个JS文件分别改成module.exports对应的代码

复制代码代码如下:
//修改后的2_modules_diff_exports.js源码如下
varcounter =0;    
module.exports=function(){   
   counter+=10;
   this.printNextCount=function()
   {
       console.log(counter);   
   }
}
varisEq=(exports===module.exports);
console.log(isEq);

复制代码代码如下:
//修改后的2_modules_diff_exports_load.js文件源码如下
varCounter=require("./2_modules_diff_exports");
varcounterObj=newCounter();
counterObj.printNextCount();

   调用后,执行结果如上图

   我在2_modules_diff_exports_load.js文件中输出了isEq的值 (varisEq=(exports===module.exports);),返回的false,这与用先前得到的结果不一致!

   PS:不要用Counter.printNextCount();去访问,你只会得到一个错误的提示

   API提供了解释

   http://nodejs.org/api/modules.html

   Notethatexportsisareferencetomodule.exportsmakingitsuitableforaugmentationonly.Ifyouareexportingasingleitemsuchasaconstructoryouwillwanttousemodule.exportsdirectlyinstead
   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

  返回该模块引用的所有模块对象的数组