很多時(shí)候,你會(huì)看到,在Node環(huán)境中,有兩種方法可以在一個(gè)模塊中輸出變量:
方法一:對(duì)module.exports賦值:
// hello.js
function hello() {
? ? ? ?console.log('Hello, world!');
}
function greet(name) {
? ? ? ??console.log('Hello, ' + name + '!');
}
module.exports = {
? ? ? ?? hello: hello,
? ? ? ?? greet: greet
};
方法二:直接使用exports:
exports.hello = hello;
exports.greet = greet;
但是你不可以直接對(duì)exports賦值:
// 代碼可以執(zhí)行,但是模塊并沒有輸出任何變量:
exports = {
? ? ? ? hello: hello,
? ? ? ? greet: greet
};
如果你對(duì)上面的寫法感到十分困惑,不要著急,我們來分析Node的加載機(jī)制:
首先,Node會(huì)把整個(gè)待加載的hello.js文件放入一個(gè)包裝函數(shù)load中執(zhí)行。在執(zhí)行這個(gè)load()函數(shù)前,Node準(zhǔn)備好了module變量:
var module = {
? ? ? ? id: 'hello',
? ? ? ? exports: {}
};
load()函數(shù)最終返回module.exports:
var load = function (exports, module) {
// hello.js的文件內(nèi)容
...
// load函數(shù)返回:
return module.exports;
};
var exported = load(module.exports, module);
也就是說,默認(rèn)情況下,Node準(zhǔn)備的exports變量和module.exports變量實(shí)際上是同一個(gè)變量,并且初始化為空對(duì)象{},于是,我們可以寫:
exports.foo = function () { return 'foo'; };
也可以寫:
module.exports.foo = function () { return 'foo'; };
換句話說,Node默認(rèn)給你準(zhǔn)備了一個(gè)空對(duì)象{},這樣你可以直接往里面加?xùn)|西。
但是,如果我們要輸出的是一個(gè)函數(shù)或數(shù)組,那么,只能給module.exports賦值:
module.exports = function () { return 'foo'; };
給exports賦值是無效的,因?yàn)橘x值后,module.exports仍然是空對(duì)象{}。
結(jié)論
如果要輸出一個(gè)鍵值對(duì)象{},可以利用exports這個(gè)已存在的空對(duì)象{},并繼續(xù)在上面添加新的鍵值;
如果要輸出一個(gè)函數(shù)或數(shù)組,必須直接對(duì)module.exports對(duì)象賦值。
所以我們可以得出結(jié)論:直接對(duì)module.exports賦值,可以應(yīng)對(duì)任何情況:
module.exports = {
? ? ? ? ?foo: function () {
? ? ? ? ?? ? ? ? ?return 'foo';
? ? ? ? ?}
};
或者:
module.exports = function () { return 'foo'; };
建議使用module.exports = xxx的方式來輸出模塊變量,這樣,你只需要記憶一種方法。