Node中的module和require

Node中的模块

在Node中,很大的一个组成部分就是模块,其中有Node中的core模块,有从npm上下载的第三方模块以及我们自己写的模块。
NodeJS在模块化方面使用的是exports和require来导入和导出。

这里我写了几个小例子来和大家分享一下exports的几种简单方法。文件目录大概是这样

module_example.png

1.直接导出

./modules/hello1.js

1
2
3
module.exports = function(){
console.log('hello world 1')
};

这是一种很简单的到处方法,module.expots可以理解成是一个空对象({}),而导出的方法就是直接用自己写好的function或者
object来替换这个对象。

./app.js

1
2
var hello1 = require('./modules/hello1');
hello1();

2.作为exports的一个属性导出

./modules/hello2.js

1
2
3
4
5
var hello = function(){
console.log('hello world 2');
};

module.exports.hello = hello;

为module.exports增加一个名为hello的属性

./app.js

1
2
var hello2 = require('./modules/hello2');
hello2.hello();

3. 用一个实例来替换module.exports

./modules/hello3.js

1
2
3
4
5
6
7
8
var hello3 = function(){
this.word = 'hello world 3';
this.hello = function(){
console.log(this.word)
}
};

module.exports = new hello3();

这里可以看到,首先我们写一个构造函数用来生成实例,然后把一个新生成的实例赋给module.exports,就像这样:

./app.js

1
2
var hello3a = require('./modules/hello3');
hello3a.hello();

但是,如果我们改变hello3a的属性会怎么样呢?按理说实例都是各自独立的,hello3a的属性改变了应该不会影响其他的实例啊,
让我们来做个实验吧

  • ./app.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var hello3a = require('./modules/hello3');
    hello3a.hello();
    //这里word属性已经改变了
    hello3a.word = 'Good bye';

    var hello3b = require('./modules/hello3');
    hello3b.hello();

    //输出是这样的
    //hello world 3
    //Good bye
    为什么啊?!我不是只改变了hello3a的word属性吗,为什么hello3b也会受到影响?!
    其实,module.exports是有缓存机制的,只要一个模块生成了一次,之后所有对这个模块的require都会判断是否存在这个模块的缓存,
    如果有,就会返回这份缓存。也就是说,不管一个模块被require多少次,其实都是require的同一个模块。那么上面的例子我该怎么让这两个实例
    真正的做到独立存在呢?

4. 导出一个构造函数

./modules/hello4.js

1
2
3
4
5
6
7
8
var HelloCreator = function(){
this.word = 'hello world 4';
this.hello = function(){
console.log(this.word);
}
};

module.exports = HelloCreator;

其实很简单,只要导出那个构造函数就行了,谁需要实例就去自己new吧

./app.js

1
2
3
4
5
6
7
8
var Hello = require('./modules/hello4');
var hello4a = new Hello();

hello4a.word = 'Good bye';
hello4a.hello();

var hello4b = new Hello();
hello4b.hello();

当然了,我们不能直接使用这个模块,因为它仅仅只是个构造函数,所以只要new一下就可以了。

5. 只把想要暴露的方法和属性暴露出去

./modules/hello5.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var word = 'Hello world 5';
var word2 = 'Good bye';

var hello = function(){
console.log(word);
};

var bye = function(){
console.log(word2);
};

module.exports = {
hello: hello,
bye: bye
};

在这个例子里,我们只把hello和bye这两个方法暴露给外界,对于其他的属性和方法,外界是无法访问到的。这样做在某种意义上保证了隐秘数据不会被外界
访问到,而且还增加了模块的可控性。

./app.js

1
2
3
var hello5 = require('./modules/hello5');
hello5.hello();
hello5.bye();

总结

定义模块和获得模块的方法有很多,以上只是列举了几种比较常见的,希望能对新入坑的小伙伴们有所帮助。其实我认为没有哪种方法是绝对好或者绝对不好的
具体使用哪种方法写模块或者导出模块还是要看具体的业务需求。