经过Node.js的官方API能够看到Node.js自己提供了不少核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,能够require('模块名')去获取;核心模块具备最高的加载优先级(有模块与核心模块同名时会体现),如:node
var fs=require('fs'); var http=require('http')
文件模块访问方式经过require('/文件名.后缀') require('./文件名.后缀') requrie('../文件名.后缀') 去访问,文件后缀能够省略;以"/"开头是以绝对路径去加载,以"./"开头和以"../"开头表示以相对路径加载,而以"./"开头表示同级目录下文件,如:api
var myadd=require('./add'); //本目录下的add.js
exports和module.exports;提供了外部访问的接口缓存
(本文讲exports和module.exports,是对外暴露文件,再引用,属于文件模块。核心模块由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;
一个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对外公开的方法均可以访问,但有区别ui
module.exports才是真正的接口,exports只不过是它的一个辅助工具。 最终返回给调用的是module.exports而不是exports。
全部的exports收集到的属性和方法,都赋值给了Module.exports。固然,这有个前提,就是module.exports自己不具有任何属性和方法。
若是,module.exports已经具有一些属性和方法,那么exports收集来的信息将被忽略。this
我把exports和 module.exports都打印出来看看究竟spa
① (虽然这样在引入模块时会报错,但这一步能说明问题,后面说缘由)3d
var counter = 0; exports.temp = function(){ counter += 10; this.printNextCount = function() { console.log(counter); } } var isEq = (exports === module.exports); console.log(exports); console.log(module.exports); console.log(isEq);
结果:code
经过exports导出的方法,会传递给module.exports。两者没区别
var counter = 0; module.exports = function(){ counter += 10; this.printNextCount = function() { console.log(counter); } } var isEq = (exports === module.exports); console.log(exports); console.log(module.exports); console.log(isEq);
结果:
直接传给module.exports,那exports就说明都没有,两者不相等了。
③:注意,导入时有点区别。和上面第一大点不同
如这里的②
var Counter = require('./ '); var counterObj = new Counter(); counterObj.printNextCount();
而第一大点能够直接这样:
var counter = require('./1_modules_custom_counter'); console.log('第二次调用模块[1_modules_custom_counter]'); counter.printNextCount();
就是要new一个对象!
由于导出的文件中的函数变成了成员方法,因此要new一个对象,再调用成员方法。
说明①不可行的缘由:当我在别的文件调用它时,不管是直接调用,仍是new一个对象再调用,都报错!
因此,要遵循这两点
1.最好别分别定义module.exports和exports
2.NodeJs开发者建议导出对象用module.exports,导出多个方法和变量用exports
三、exports和module.exports覆盖
直接上代码,看谁留下,谁消失
var counter = 0; exports.printNextCount = function() { counter+=2; console.log(counter); } module.exports = function(){ counter+=10; this.printNextCount=function(){ console.log(counter) } } var isEq = (exports === module.exports); console.log(exports); console.log(module.exports); console.log(isEq);
想一想都知道谁厉害。
引用该模块:
①报错,说明exports的消失了
var counter = require('./test3'); counter.printNextCount();
②留下了。
var counter = require('./test3'); var counterObj=new counter() counterObj.printNextCount();
结果,输出了它成功导出的对象函数值;前面两个是两个接口收集到的东西,最后exports的被覆盖了
exports仅仅是module.exports的一个地址引用。nodejs只会导出module.exports的指向,若是exports指向变了,那就仅仅是exports不在指向module.exports,因而不会再被导出
至关于:a和b指向同一块内存,b是a的地址引用
var a = new Object();//a至关于module.exports var b = a; //b至关于exports
覆盖,也就是a已经赋值了,但b又被赋了别的值。这时候,b就是叛变了,就指向了一块新的地址了。而模块引用是要用module.exports来引用,因此指向新地址的exports不起做用了。