NodeJS 学习体会分享(2)模块和包深入理解

模块(Module)和包(Package)是 Node.js最重要的支柱。开发一个具有一定规模的程序不可能只用一个文件,通常需要把各个功能拆分、封装,然后组合起来,模块正是为了实现这种方式而诞生的。在浏览器 JavaScript 中,脚本模块的拆分和组合通常使用 HTML 的script 标签来实现。Node.js提供了require函数来调用其他模块,而且模块都是基于文件的,机制十分简单。

其实本质上模块和包没有太大的区别,我们可以把包理解和成某一个功能模块的集合,用于发布和维护。

创建模块

使用Node.js可以很快创建一个模块,我们之前说了一个文件就是一个模块,我们知道如何在其他文件中获取这个模块。Node.js中提供了exports和require两个对象,其中exports是模块公开的接口,require用于从外部获取一个模块的接口,即所获取模块的exports对象。

下面我们就来试一试,创建一个名为module.js的文件:

1
2
3
4
5
6
7
8
9
var name;
exports.setName = function(tName){
name = tName;
};
exports.sayHello = function(){
console.log("Hello , "+name);
}

同时创建测试程序testModule.js:

1
2
3
4
var myModule = require('./module');
myModule.setName("xhay");
myModule.sayHello();

运行node testModule.js,得到结果

Hello , xhay

在上面这个例子中,我们通过exports把setName和sayHello作为模块外部访问的接口,然后我们通过require来加载这个模块,然后就可以使用了。

模块是单次加载的

通过require并不会重复的加载模块,也就是说无论多少次调用require,获得的模块都是同一个。

我们修改测试程序testModule.js:

1
2
3
4
5
6
7
var myModule1 = require('./module');
myModule1.setName("xhay1");
var myModule2 = require('./module');
myModule2.setName("xhay2");
myModule1.sayHello();

运行node testModule.js,得到结果

Hello , xhay2

我们期望的到Hello , xhay1,但实际结果并不是这样的。所以通过require模块式单次加载的。

exports 和 module.exports 区别

1、exports 是指向 module.exports的引用。
2、module.exports 和 exports的初始值为一个空对象{}。
3、require()返回的是module.exports而不是exports。

举例说明:

使用exports:

speck.js

1
2
3
exports.sayHello = function(name) {
console.log("hello "+name);
}

test.js

1
2
var speck = require('./speck');
speck.sayHello("xhay"); //使用方法

使用module.exports:
speck.js

1
2
3
module.exports = function(name) {
console.log("hello "+name);
}

test.js

1
2
var speck = require('./speck');
speck("xhay"); //使用方法

如果把使用exports的例子稍微改一下

speck.js

1
2
3
exports = function(name) {
console.log("hello "+name);
}

test.js

1
2
var speck = require('./speck');
speck("xhay"); //使用方法

这个例子就会报错,因为在前面的例子当中我们都是给exports添加属性,只是对exports指向的内存做了修改,exports和module.exports指向的值依旧相同。而这个例子覆盖了exports,此时exports和module.exports指向的不同的值,所以我们在通过require获取的时候,依旧是个空对象{};

具体区别参考资料:exports和module.exports的区别;