Node.jsモジュールに次の規約が見つかりました。
module.exports = exports = nano = function database_module(cfg) {...}
module.exports
とexports
の違い、そしてなぜここで両方が使われているのでしょうか。
module.exports
を設定すると、required
のときにdatabase_module
関数を関数のように呼び出すことができます。 nodeがオブジェクトのmodule.exports
参照をエクスポートするので、単にexports
を設定しても関数をエクスポートすることはできません。次のコードでは、ユーザーは関数を呼び出すことができません。
以下は動作しません。
exports = nano = function database_module(cfg) {return;}
module.exports
が設定されている場合、以下は動作します。
module.exports = exports = nano = function database_module(cfg) {return;}
コンソール
var func = require('./module.js');
// the following line will **work** with module.exports
func();
基本的に node.js は、exports
が現在参照しているオブジェクトをエクスポートしませんが、exports
が最初に参照しているオブジェクトのプロパティをエクスポートします。 Node.js はオブジェクトのmodule.exports
参照をエクスポートしますが、関数のように呼び出すことができます。
exports
が以前にエクスポートされたオブジェクトを参照しないようにするために、module.exports
とexports
の両方を設定します。両方を設定することで、あなたはexports
を速記として使用し、将来の潜在的なバグを避けることができます。
exports.prop = true
の代わりにmodule.exports.prop = true
を使用すると文字が節約され混乱を避けることができます。
質問がずっと前に回答され、受け入れられたにもかかわらず、私はちょうど私の2セントを共有したいです。
あなたはあなたのファイルの最初に(説明のためだけに)次のようなものがあると想像することができます。
var module = new Module(...);
var exports = module.exports;
ですから、module.exports
とNOT exports
は、他の場所からそのモジュールを要求しているときに返されることに注意してください。
だからあなたが何かをするとき:
exports.a = function() {
console.log("a");
}
exports.b = function() {
console.log("b");
}
Module.exportsが指すオブジェクトにも2つの関数 'a'と 'b'を追加しているので、返される結果のtypeof
はobject
になります。{ a: [Function], b: [Function] }
もちろん、この例でexports
の代わりにmodule.exports
を使用している場合と同じ結果になります。
これは、module.exportsをエクスポートされた値のコンテナのように動作させたい場合です。一方、コンストラクタ関数だけをエクスポートしたい場合は、module.exports
またはexports
を使用することについて知っておくべきことがあります(必要であればmodule.exportsが返され、エクスポートはされません)。
module.exports = function Something() {
console.log('bla bla');
}
結果を返すtypeofは'function'
であり、それを要求してすぐに次のように呼び出すことができます。var x = require('./file1.js')();
は、返された結果を関数に上書きするためです。
しかし、exports
を使用すると、以下のようなものは使用できません。
exports = function Something() {
console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function
exports
では、参照はmodule.exports
が指すオブジェクトをもう「ポイント」していないので、exports
とmodule.exports
の間にはもう関係がありません。この場合、module.exportsはまだ返される空のオブジェクト{}
を指しています。
他のトピックからの承認された回答も役に立つでしょう: Javascriptは参考文献として渡しますか?
基本的に答えは、モジュールがrequire
ステートメントによって要求されたときに実際に起こることにあります。モジュールが必要とされるのはこれが初めてだと仮定します。
例えば:
var x = require('file1.js');
file1.jsの内容
module.exports = '123';
上記のステートメントが実行されると、Module
オブジェクトが作成されます。そのコンストラクタ関数は次のとおりです。
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.Push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
ご覧のとおり、各モジュールオブジェクトはexports
という名前のプロパティを持ちます。これがrequire
の一部として最終的に返されるものです。
Requireの次のステップは、file1.jsの内容を以下のような無名関数にラップすることです。
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
});
そして、この無名関数は次のように呼び出されます。ここでmodule
は、以前に作成されたModule
オブジェクトを指します。
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");
関数の内部でわかるように、exports
仮引数はmodule.exports
を参照しています。要するにそれはモジュールプログラマに提供される便利さです。
しかしながら、この便利さは慎重に行使される必要があります。いずれにせよ、エクスポートに新しいオブジェクトを割り当てようとするならば、確実にこうします。
exports = module.exports = {};
間違った方法 のようにしても、module.exports
はまだモジュールインスタンスの一部として作成されたオブジェクトを指しています。
exports = {};
結果として、上記のexportsオブジェクトに何かを追加してもmodule.exportsオブジェクトには影響がなく、requireの一部としてエクスポートも返されることもありません。
最初は、module.exports=exports
とrequire
関数が、module.exports
が参照するオブジェクトを返します。
オブジェクトにプロパティ を追加する場合、exports.a=1
を指定すると、module.exportsとexports それでも は同じオブジェクトを参照します。したがって、requireを呼び出してモジュールを変数に割り当てると、変数はプロパティaを持ち、その値は1になります。
しかし、exports=function(){}
のように、 override のいずれかであれば、 different になります。exportsは新しいオブジェクトを、module.exportsは元のオブジェクトを参照します。また、ファイルが必要な場合は、module.exportsが新しいオブジェクトを参照しないため、新しいオブジェクトは返されません。
私にとっては、私は新しいプロパティを追加し続けるか、またはそれらの両方を新しいオブジェクトにオーバーライドします。上書きするだけでは正しくありません。そしてmodule.exports
が本当のボスだということを覚えておいてください。
exports
とmodule.exports
は、モジュール内でexports
を再割り当てしない限り同じです。
これについて考える最も簡単な方法は、この行がすべてのモジュールの先頭にあることを暗黙的に考えることです。
var exports = module.exports = {};
モジュール内でexports
を再割り当てすると、モジュール内でそれが再割り当てされ、もはやmodule.exports
と等しくなりません。これが、あなたが関数をエクスポートしたいのなら、あなたがしなければならない理由です:
module.exports = function() { ... }
単にあなたのfunction() { ... }
をexports
に代入したならば、あなたはもはやmodule.exports
を指さないようにexports
を再割り当てするでしょう。
毎回module.exports
で関数を参照したくない場合は、次のようにします。
module.exports = exports = function() { ... }
module.exports
が一番左の引数です。
exports
にプロパティを付けることは、あなたがそれを再割り当てしていないので同じではありません。これがこれが機能する理由です
exports.foo = function() { ... }
JavaScriptでオブジェクトが参照渡しされる方法とは微妙な違いがあります。
exports
とmodule.exports
はどちらも同じオブジェクトを指しています。 exports
は変数、module.exports
はモジュールオブジェクトの属性です。
私はこのようなものを書くとしましょう:
exports = {a:1};
module.exports = {b:12};
exports
とmodule.exports
は異なるオブジェクトを指すようになりました。エクスポートを変更してもmodule.exportsは変更されなくなりました。
インポート関数がmodule.exports
を調べるとき、それは{b:12}
を得ます
ちょっとテストしてみると、nodejsのモジュールコードの中では、次のようになるはずです。
var module.exports = {};
var exports = module.exports;
そう:
exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.
exports.abc = function(){}; // works!
exports.efg = function(){}; // works!
module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = 'value a'; // works
exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)
これは node.jsの中のノードモジュールについて書かれた良い説明です book from Manning publication。
アプリケーションで最終的にエクスポートされるのは、 module.exports。
輸出 は、単にグローバルな参照として設定されています。 module.exports これは、最初はプロパティを追加できる空のオブジェクトとして定義されています。そう exports.myFunc ただの略記です module.exports.myFunc。
結果として、 輸出 他に設定されている場合、 参照 の間に module.exports そして 輸出 。なぜなら module.exports 本当にエクスポートされるのは 輸出 期待どおりに機能しなくなります。参照できません。 モジュール.exports もう。そのリンクを維持したい場合は、次のようにします。 module.exports 参照 輸出 また次のように:
module.exports = exports = db;
私はいくつかのテストを経験しました、そしてこれは主題にいくらかの光を当てるかもしれないと思います...
app.js
:
var ...
, routes = require('./routes')
...;
...
console.log('@routes', routes);
...
/routes/index.js
のバージョン:
exports = function fn(){}; // outputs "@routes {}"
exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }"
module.exports = function fn(){}; // outputs "@routes function fn(){}"
module.exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }"
私も新しいファイルを追加しました:
./routes/index.js
:
module.exports = require('./not-index.js');
module.exports = require('./user.js');
./routes/not-index.js
:
exports = function fn(){};
./routes/user.js
:
exports = function user(){};
出力は "@routes {}"です。
./routes/index.js
:
module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');
./routes/not-index.js
:
exports = function fn(){};
./routes/user.js
:
exports = function user(){};
"@routes {fn:{}、user:{}}"という出力が得られます。
./routes/index.js
:
module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');
./routes/not-index.js
:
exports.fn = function fn(){};
./routes/user.js
:
exports.user = function user(){};
user.js
を{ ThisLoadedLast: [Function: ThisLoadedLast] }
に変更すると、出力「@routes {ThisLoadedLast:[Function:ThisLoadedLast]}」が得られます。
しかし、./routes/index.js
...を変更した場合.
./routes/index.js
:
module.exports.fn = require('./not-index.js');
module.exports.ThisLoadedLast = require('./user.js');
./routes/not-index.js
:
exports.fn = function fn(){};
./routes/user.js
:
exports.ThisLoadedLast = function ThisLoadedLast(){};
... "@routes {fn:{fn:[関数:fn]}、ThisLoadedLast:{ThisLoadedLast:[関数:ThisLoadedLast]}}"となります。
だから私はあなたのモジュール定義で常にmodule.exports
を使うことを勧めます。
Nodeの内部で何が起こっているのか完全には理解できていませんが、役に立つと確信しているのでもっと理解できる場合はコメントしてください。
- ハッピーコーディング
これは次の結果です。
console.log("module:");
console.log(module);
console.log("exports:");
console.log(exports);
console.log("module.exports:");
console.log(module.exports);
また:
if(module.exports === exports){
console.log("YES");
}else{
console.log("NO");
}
//YES
注:CommonJS仕様では、publicメンバーを公開するためのexports変数の使用のみが許可されています。したがって、名前付きエクスポートパターンは、CommonJS仕様と本当に互換性のある唯一のパターンです。 module.exportsの使用は、より広範囲のモジュール定義パターンをサポートするためにNode.jsによって提供される拡張機能です。
var a = {},md={};
//まず、exportsとmodule.exportsが同じ空のObjectを指しています
exp = a;//exports =a;
md.exp = a;//module.exports = a;
exp.attr = "change";
console.log(md.exp);//{attr:"change"}
//もしあなたがexpを他のオブジェクトにポイントするのではなく他のオブジェクトにポイントするならば、それは他のオブジェクトに対するプロパティです。 md.expは空になりますObject {}
var a ={},md={};
exp =a;
md.exp =a;
exp = function(){ console.log('Do nothing...'); };
console.log(md.exp); //{}
このリンクは上記の質問に回答するのに役立ちます。
http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/
他の投稿に追加するにはノード内のモジュールシステムは
var exports = module.exports
コードを実行する前にですから、exports = fooを使いたいときは、おそらくmodule.exports = exports = fooを使いたいでしょうが、exports.foo = fooを使っても大丈夫です。
これは Eloquent JavaScript からの抜粋で、どのようにrequire()
がその最も単純な形で機能するかを示しています
問題 モジュールが関数などのエクスポートオブジェクト以外の値を直接エクスポートすることはできません。たとえば、モジュールが定義したオブジェクト型のコンストラクタだけをエクスポートしたい場合があります。現在、それはできません。requireは常にエクスポートされた値として作成するexports
オブジェクトを使用するためです。
解決策 別の変数module
をモジュールに提供します。これは、プロパティexports
を持つオブジェクトです。このプロパティは最初はrequireによって作成された空のオブジェクトを指していますが、他の値をエクスポートするために別の値で上書きすることができます。
function require(name) {
if (name in require.cache)
return require.cache[name];
var code = new Function("exports, module", readFile(name));
var exports = {}, module = {exports: exports};
code(exports, module);
require.cache[name] = module.exports;
return module.exports;
}
require.cache = Object.create(null);
docs から
Exports変数はモジュールのファイルレベルスコープ内で利用可能で、モジュールが評価される前にmodule.exportsの値が割り当てられます。
ショートカットを許可するので、module.exports.f = ...はexports.f = .... のようにもっと簡潔に書くことができます。ただし、新しい値がエクスポートに割り当てられ、module.exportsにバインドされなくなりました。
これは単にmodule.exportsを指す変数です
「モジュールのエクスポートのルートを関数(コンストラクタなど)にする場合や、一度に1つのプロパティを構築するのではなく、1つの割り当てで完全なオブジェクトをエクスポートする場合は、代わりにmodule.exportsに割り当てます。輸出」 - http://nodejs.org/api/modules.html
2つの方法で1つのモジュールを作りましょう。
一方通行
var aa = {
a: () => {return 'a'},
b: () => {return 'b'}
}
module.exports = aa;
第二の方法
exports.a = () => {return 'a';}
exports.b = () => {return 'b';}
そしてこれが require() がモジュールを統合する方法です。
最初の方法:
function require(){
module.exports = {};
var exports = module.exports;
var aa = {
a: () => {return 'a'},
b: () => {return 'b'}
}
module.exports = aa;
return module.exports;
}
第二の方法
function require(){
module.exports = {};
var exports = module.exports;
exports.a = () => {return 'a';}
exports.b = () => {return 'b';}
return module.exports;
}
1.exports - >シングルトンユーティリティとして使用
2。モジュールエクスポート - >サービス、モデルなどの論理オブジェクトとして使用
module.exports
とexports
は同じfunction database_module(cfg) {...}
を指しています。
1| var a, b;
2| a = b = function() { console.log("Old"); };
3| b = function() { console.log("New"); };
4|
5| a(); // "Old"
6| b(); // "New"
3行目のb
をa
に変更できます。出力は逆になります。結論は次のとおりです。
a
とb
は独立しています。
それでmodule.exports = exports = nano = function database_module(cfg) {...}
は以下と同等です。
var f = function database_module(cfg) {...};
module.exports = f;
exports = f;
上記はmodule.js
であると仮定します。これはfoo.js
に必要です。 module.exports = exports = nano = function database_module(cfg) {...}
の恩恵は今明らかです。
foo.js
では、module.exports
はrequire('./module.js')
なので、
var output = require('./modules.js')();
moduls.js
:module.exports
の代わりにexports
を使うことができます。
exports
とmodule.exports
の両方が同じものを指しているのであれば、嬉しいでしょう。
module.exports
とexports
は両方とも、モジュールが評価される前に同じオブジェクトを指します。
モジュールがrequire
ステートメントを使用して別のモジュールで使用されている場合、module.exports
オブジェクトに追加するプロパティはすべて使用可能になります。 exports
は、同じものに使用できるショートカットです。例えば:
module.exports.add = (a, b) => a+b
書くことと同等です:
exports.add = (a, b) => a+b
したがって、exports
変数に新しい値を割り当てない限り問題ありません。このようなことをするとき:
exports = (a, b) => a+b
新しい値をexports
に割り当てると、エクスポートされたオブジェクトへの参照がなくなり、モジュールに対してローカルのままになります。
使用可能になった初期オブジェクトに新しいプロパティを追加するのではなく、module.exports
に新しい値を割り当てることを計画している場合は、おそらく次のようにすることを検討する必要があります。
module.exports = exports = (a, b) => a+b
node jsのmodule.jsファイルは、nodeがファイルを実行するたびにmodule.load system.eを実行するために使用され、次のようにjsファイルの内容をラップします。
'(function (exports, require, module, __filename, __dirname) {',+
//your js file content
'\n});'
これはur jsのソースコードの中に入っているので、export、require、moduleなどにアクセスできます。jsファイルに書いた機能を別の方法で書く方法は他にはないので、このアプローチが使われます。
その後、nodeはc ++を使用してこのラップされた関数を実行します。その時点で、この関数に渡されたオブジェクトはエクスポートされます。
あなたはこの関数のパラメータのエクスポートとモジュールの内側を見ることができます。実際にエクスポートはモジュールコンストラクター関数のパブリックメンバーです。
次のコードを見てください
このコードをb.jsにコピーしてください。
console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log('----------------------------------------------');
var foo = require('a.js');
console.log("object.keys of foo: "+Object.keys(foo));
console.log('name is '+ foo);
foo();
このコードをa.jsにコピーしてください。
exports.name = 'hello';
module.exports.name = 'hi';
module.exports.age = 23;
module.exports = function(){console.log('function to module exports')};
//exports = function(){console.log('function to export');}
今ノードを使用して実行します
module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true
foo:nameのobject.keysはfunction(){console.log( '関数からモジュールへのエクスポート')}関数からモジュールへのエクスポート
a.jsのコメント行を削除し、その行の上の行をコメントアウトしてb.jsの最後の行を削除して実行します。
javaScriptの世界では、パラメータとして渡されたオブジェクトを再割り当てすることはできませんが、その関数のオブジェクトが別の関数のパラメータとして設定されている場合は、その関数のパブリックメンバーを変更できます。
module.exportsを使用するのは、requireキーワードを使用するときに関数を取得したい場合だけにしてください。上記の例では、foo = require(a.js)とします。関数としてfooを呼び出せることがわかります。
これはノードのドキュメンテーションが「exportsオブジェクトはModuleシステムによって作成されます。時々これは受け入れられない、彼らのモジュールがあるクラスのインスタンスになることを望んでいます。これを行うには望ましいモジュールをmodule.exportsに割り当てます」