模块导出——仅对象
main.js
var fooExports = require('./foo');
// ReferenceError: foo is not defined
// console.log(foo);
// 这种方式导出的都是对象
// { add: [Function: add], foo: 'bar', str: 'hello world' }
console.log(fooExports);
foo.js
var foo = 'bar';
function add(x, y) {
return x + y;
}
// 只能得到我想要给你的成员
// 这样做的目的是为了解决变量命名冲突的问题
exports.add = add;
// exports 是一个对象
// 我们可以通过多次为这个对象添加成员实现
exports.foo = foo;
exports.str = 'hello world';
模块导出——其他类型
现在,我有另一个需求:
希望加载得到直接就是一个:
- 方法
- 字符串
- 数字
- 数组
main.js
var fooExports = require('./foo');
console.log(fooExports);
foo.js
function add(x, y) {
return x + y;
}
// exports = add;//没用
// 如果某个模块需要直接导出某个成员,而非挂载的方式
// 那这个时候必须使用下面的方式
// module.exports = add;// [Function: add]
module.exports = 'hello';// hello
// 注意:重复写会后面的覆盖前面的(hello 被覆盖掉了)
module.exports = function (x, y) {
return x + y;
};// [Function]
// 通过对象的方式导出多个成员
module.exports = {
a: function (x, y) {
return x + y;
},
b: 'hello',
};// { a: [Function: a], b: 'hello' }
模块系统原理
在 Node 中,每个模块内部都有一个自己的 module 对象,该对象中有个成员 exports 也是对象
// 类似于这个
var module = {
exports: {
foo: 'bar'
}
};
如果你需要对外导出成员,只需要把导出的成员挂载到 module 对象上去
// module.exports.foo = 'bar';
// module.exports.add = function (x, y) {
// return x + y;
// };
// 上面那种方法点的太多了,所有 node.js 提供了 exports === module.exports
console.log((exports === module.exports));// true
// 所以可以简化为
exports.foo = 'bar';
exports.add = function (x, y) {
return x + y;
};
require 时就相当于默认在代码最后添加一句:return module.exports
// 另一个 js 文件获取
var fooExports = require('./foo');
console.log(fooExports);// { foo: 'bar', add: [Function] }
所以想要导出其他类型的数据
// 相当于把 exports 对象类型重新定义了
module.exports = 'hello';
而实际用的时候:
- 导出多个成员:
exports.xxx = xxx
- 导出多个成员也可以:
module.exports = { a:xxx, b:xxx }
- 导出单个成员:
module.exports = 'hello'
注意:如果实在分不清 exports 和 module.exports,那就选择忘记 exports,而只使用 module.exports 也没问题
导出文件路径及路径名
foo.js 中
console.log(__filename);
console.log(__dirname);
main.js 中引用 foo.js 就会打印出来:
exports 和 module.exports 的区别
每个模块中都有一个 module 对象
module 对象中有一个 exports 对象
我们可以把需要导出的成员都挂载到 module.exports 接口对象中
也就是:moudle.exports.xxx = xxx
的方式
但是每次都moudle.exports.xxx = xxx
很麻烦,点儿的太多了
所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:exports
exports === module.exports
结果为true
所以对于:moudle.exports.xxx = xxx
的方式 完全可以:expots.xxx = xxx
当一个模块需要导出单个成员的时候,这个时候必须使用:module.exports = xxx
的方式
不要使用exports = xxx
不管用
因为每个模块最终向外return
的是module.exports
而exports
只是module.exports
的一个引用
所以即便你为exports = xx
重新赋值,也不会影响module.exports
但是有一种赋值方式比较特殊:exports = module.exports
这个用来重新建立引用关系的
node 中的其他成员
在每个模块中,除了 require
、exports
等模块相关的 API 之外,还有两个特殊的成员:
__dirname
可以用来 动态获取 当前文件模块所属目录的绝对路径__filename
可以用来 动态获取 当前文件的绝对路径(包含当前文件的文件名)
出现目的:解决 node 中 ./a.txt
读取文件只是相对于执行 node 命令所处的路径
fun.js
- code
index.js
a.txt
如果通过 fun.js
调用 index.js
读取文件 a.txt
,执行顺序为 fun.js
>> index.js
>> a.txt
,那么 node 调用 fun.js
,执行到 index.js
便会出错,因为 a.txt
的读取会在 fun.js
去寻找
所以为了解决这个问题,把相对路径转换为绝对路径,在 index.js
中,便可以用 __dirname + '/a.txt'
代替 ./a.txt
,为了避免手动拼接带来的一些低级错误,推荐用 path 模块的 path.join(__dirname,'./a.txt')
注意:模块中的路径标识 require
不受影响(文件的读取 fs.readFile()
会出现上面错误)