模块中exports
在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分。狭义的说,每一个JavaScript文件都是一个模块;而多个JavaScript文件之间可以相互require,他们共同实现了一个功能,他们整体对外,又称为一个广义上的模块。
Node.js中,一个JavaScript文件中定义的变量、函数,都只在这个文件内部有效。当需要从此JS文件外部引用这些变量、函数时,必须使用exports对象进行暴露。使用者要用require()命令引用这个JS文件。如下实例:
foo.js文件中的代码:
var msg = "你好"; //msg这个变量,是一个js文件内部才有作用域的变量,如果别人想用这个变量,那么就要用exports进行暴露。 exports.msg=msg;
使用者:
var foo = require("./foo.js"); //使用者用foo来接收exports对象,也就是说,这里的foo变量,就是文件中的exports变量。 console.log(foo.msg);
一个JavaScript文件,可以向外exports无数个变量、函数。但是require的时候,仅仅需要require这个JS文件一次。使用的它的变量、函数的时候,用点语法即可。所以,无形之中,增加了一个顶层命名空间。所有的函数、变量都要从这个顶层变量走:
如下实例:
var msg = "你好"; var info = "呵呵"; function showInfo(){ console.log(info); } exports.msg = msg; exports.info = info; exports.showInfo = showInfo;
在使用者中,只需要require一次。
var foo = require("./foo.js"); console.log(foo.msg); console.log(foo.info); foo.showInfo();
exports和module.export的区别
对于module.exports与exorts的区别,了解了下面几点之后应该就完全明白:
模块内部大概是这样:
exports = module.exports = {};
- exports是module.exports的一个引用
- require引用模块后,返回给调用者的是module.exports而不是exports
exports.xxx
,相当于在导出对象上挂属性,该属性对调用模块直接可见exports =
相当于给exports对象重新赋值,调用模块不能访问exports对象及其属性- 如果此模块是一个类,就应该直接赋值
module.exports
,这样调用者就是一个类构造器,可以直接new实例
我们经常看到这样的写法:
exports = module.exports = somethings
上面的代码等价于:
module.exports = somethings
exports = module.exports
即 module.exports 指向新的对象时,exports 断开了与 module.exports 的引用,那么通过 exports = module.exports 让 exports 重新指向 module.exports 即可。
结论:
- 对于要导出的属性,可以简单直接挂到
exports
对象上 - 对于类,为了直接使导出的内容作为类的构造器可以让调用者使用new操作符创建实例对象,应该把构造函数挂到
module.exports
对象上,不要和导出属性值混在一起
require
- 在require中,如果没有写./,则该路径不是一个相对路径。那么Node.js将该文件视为node_modules目录下的一个文件
var foo = require("foo.js"); //没有写./, 所以不是一个相对路径。则node将会从node_modules这个文件夹下面去选择foo.js这个文件
node_modules文件夹并不一定在同级目录里面,在任何直接祖先级目录中,都可以。甚至可以放到NODE_PATH环境变量的文件夹中。这样做的好处是,分享项目的时候,不需要带着modules一起给别人。
- 我们可以使用文件夹来管理模块,如果require中,引入的是一个文件夹,那么Node.js将会去寻找node_modules目录下的该文件夹中的index.js去执行。如下实例
var bar = require("bar"); //node将会去查找node_modules下的bar文件夹中的index.js执行
关于路径问题
require()中的路径,是从当前这个js文件出发,找到别人。而fs等其他模块是从命令提示符找到别人。
有如下结构的一个实例:
a要引用b:
var b = require(“./test/b.js”);
b要引用c:
var b = require(“./c.js”);
但是,fs等其他的模块用到路径的时候,都是相对于cmd命令光标所在位置。所以,在b.js中想读1.txt文件,如果用相对路径,并且不是在当前文件中,会报一个错,如下:
var c=require("./c.js"); var fs=require("fs") fs.readFile("./1.txt",function (err,data) { if(err) { throw err; } console.log(data.toString()); });
运行结果:
所以除了require中,nodejs中都建议采用绝对路径,如下:
var c=require("./c.js"); var fs=require("fs") fs.readFile(__dirname+"/1.txt",function (err,data) { if(err) { throw err; } console.log(data.toString()); });