module.exports vs exports
很多时候,你会看到,在Node环境中,有两种方法可以在一个模块中输出变量:
方法一:对module.exports赋值:
// hello.js
function hello() {
console.log('Hello, world!');
}
function greet(name) {
console.log('Hello, ' + name + '!');
}
function hello() {
console.log('Hello, world!');
}
module.exports = {
hello: hello,
greet: greet
};
方法二:直接使用exports:
// hello.js
function hello() {
console.log('Hello, world!');
}
function greet(name) {
console.log('Hello, ' + name + '!');
}
function hello() {
console.log('Hello, world!');
}
exports.hello = hello;
exports.greet = greet;
但是你不可以直接对 exports 赋值:
// 代码可以执行,但是模块并没有输出任何变量:
exports = {
hello: hello,
greet: greet
};
如果你对上面的写法感到十分困惑,不要着急,我们来分析Node的加载机制:
首先,Node会把整个待加载的 hello.js 文件放入一个包装函数 load 中执行。在执行这个 load() 函数前,Node准备好了module变量:
var module = {
id: 'hello',
exports: {}
};
load() 函数最终返回 module.exports :
var load = function (exports, module) {
// hello.js的文件内容
…
// load函数返回:
return module.exports;
};
var exported = load(module.exports, module);
也就是说,默认情况下,Node准备的 exports 变量和 module.exports 变量实际上是同一个变量,并且初始化为空对象 {} ,于是,我们可以写:
exports.foo = function () { return 'foo'; };
exports.bar = function () { return 'bar'; };
也可以写:
module.exports.foo = function () { return 'foo'; };
module.exports.bar = function () { return 'bar'; };
换句话说,Node默认给你准备了一个空对象 {} ,这样你可以直接往里面加东西。
但是,如果我们要输出的是一个函数或数组,那么,只能给 module.exports 赋值:
module.exports = function () { return 'foo'; };
给 exports 赋值是无效的,因为赋值后, module.exports 仍然是空对象 {} 。