在前面几篇博客中,我们始终在学习如何进行nodejs的模块化编程,nodejs中模块化编程最主要的一个特征就是常常可以在很多js文件看到require(),也就是引入其他的js文件,非常类似与其他语言中的import或include。同时如果想要require('A'),那么在A文件中必须要使用exports这个关键字表明要导出什么变量或函数。
先来看一个非常简单的使用require和exports的例子,新建一个app.js文件,代码实现如下:
//引入同一目录下的name.js
var name = require('./name');
//使用name.js中的变量
console.log(name.name1);
//调用name.js中的函数
name.getName();
同一目录下创建name.js文件,代码实现如下:
//变量
var name1 = "Jack";
//函数
function getName() {
console.log("Mary");
}
//分别导出变量和函数
module.exports.name1 = name1;
module.exports.getName = getName;
运行app.js脚本,打印结果如下:
可以看到,一个js文件可以成功访问另一个js文件的变量和函数。
其实当使用require时,可以理解为首先去执行了需要载入的js文件,所以,被载入文件的代码会首先执行一遍,现把name.js修改如下:
//变量
var name1 = "Jack";
//函数
function getName() {
console.log("Mary");
}
//如果require该文件,则会打印
console.log("Running name.js");
//分别导出变量和函数
module.exports.name1 = name1;
module.exports.getName = getName;
执行app.js脚本后,控制台中打印结果如下,可见整个name.js都被执行了。
上面的name.js还可以继续优化,如果要导出的变量或函数较多,则上面的代码稍显冗余,先把name.js修改如下:
//变量
var name1 = "Jack";
//函数
function getName() {
console.log("Mary");
}
//如果require该文件,则会打印
console.log("Running name.js");
//分别导出变量和函数
// module.exports.name1 = name1;
// module.exports.getName = getName;
//一种更优雅的导出方式,功能同上,更为简洁
module.exports = {
name1: name1,
getName: getName
};
最后的运行结构与上面相同。
其实上面的代码还可以继续优化,函数的导出可以更加简洁,name.js修改如下:
//变量
var name1 = "Jack";
//函数
// function getName() {
// console.log("Mary");
// }
//如果require该文件,则会打印
console.log("Running name.js");
//分别导出变量和函数
// module.exports.name1 = name1;
// module.exports.getName = getName;
//一种更优雅的导出方式,功能同上,更为简洁,可以把所有的变量写入
module.exports = {
name1: name1
};
//对于函数,则有更方便的导出方式,函数推荐使用这种方式,定义的时候同时导出
module.exports.getName = function () {
console.log("Mary");
};
最后我们来区分一下module.exports和exports的区别。我们在看很多nodejs代码的时候,常常看到使用这两种方式。其实module.exports和exports的区别就是var a={}; var b=a; 中a和的区别。exports指向的只是一个引用。改变exports的指向后所添加的exports.***都是无效的。因为require返回的只是module.exports. 所以不能在使用了exports.***之后,改变module.exports的指向。因为exports.***添加的属性和方法并不存在与module.exports所指向的新对象中。
个人建议,可以全部使用module.exports来应对所有的情况,并尽量减少犯错的机会。