レニーの答えはよく説明されています。例による回答への追加:
ノードはファイルに対して多くのことを行いますが、重要なものの 1 つはファイルをラップすることです。nodejs 内のソース コード「module.exports」が返されます。一歩下がって、ラッパーを理解しましょう。あなたが持っていると仮定します
あいさつ.js
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
上記のコードは、次のように nodejs ソース コード内で IIFE (Immediately Invoked Function Expression) としてラップされます。
(function (exports, require, module, __filename, __dirname) { //add by node
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
}).apply(); //add by node
return module.exports; //add by node
上記の関数が呼び出され (.apply())、module.exports が返されます。この時点で、module.exports と exports は同じ参照を指しています。
では、greet.js を次のように書き直したとします。
exports = function () {
console.log('Hello World');
};
console.log(exports);
console.log(module.exports);
出力は次のようになります
[Function]
{}
理由は次のとおりです。module.exports は空のオブジェクトです。module.exports には何も設定せず、newgreet.js で exports = function()..... を設定しました。したがって、module.exports は空です。
技術的には、エクスポートと module.exports は同じ参照を指している必要があります (正しいです!!)。しかし、function().... をエクスポートに割り当てるときに "=" を使用すると、メモリ内に別のオブジェクトが作成されます。したがって、module.exports と exports は異なる結果を生成します。エクスポートに関しては、それをオーバーライドすることはできません。
ここで、(これはミューテーションと呼ばれます)greet.js(レニーの回答を参照)を次のように書き直したとします。
exports.a = function() {
console.log("Hello");
}
console.log(exports);
console.log(module.exports);
出力は次のようになります
{ a: [Function] }
{ a: [Function] }
ご覧のとおり、module.exports と exports は関数である同じ参照を指しています。exports にプロパティを設定すると、module.exports に設定されます。これは、JS ではオブジェクトが参照渡しであるためです。
結論は、混乱を避けるために常に module.exports を使用することです。お役に立てれば。ハッピーコーディング:)