概要: このチュートリアルでは、Node.jsモジュールについて学び、その仕組みを理解します。
Node.jsモジュールの概要
Node.jsでは、モジュールとは、.jsファイルに配置された再利用可能なコードのことです。Node.jsは、2つのモジュールシステムをサポートしています。
- CommonJS
- ESモジュール (Node 14.0.0以降)。
このチュートリアルでは、CommonJSモジュールに焦点を当てます。
モジュール内で変数、関数、クラスを定義すると、これらの識別子は、そのモジュール内でのみアクセス可能になります。
これらのオブジェクトを別のモジュールで使用するには、以下のエクスポートメカニズムのいずれかを使用してエクスポートするか、それらを組み合わせる必要があります。
- 名前付きエクスポート
- デフォルトエクスポート。
名前付きエクスポート
名前付きエクスポートでは、識別子をmodule.exportsオブジェクトの個々のプロパティに割り当てます。これにより、モジュールから複数の識別子をエクスポートし、別のモジュールに個別にインポートできます。
名前付きエクスポートの使用例を見てみましょう。
まず、math.jsという新しいモジュールを、addとsubtractの2つの関数とともに作成します。
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}Code language: JavaScript (javascript)add関数とsubtract関数は、math.jsモジュール内でのみ可視です。
これらの関数を別のモジュールで使用するには、module.exportsオブジェクトのプロパティに割り当てることでエクスポートする必要があります。
次に、math.jsモジュールからadd関数とsubtract関数をエクスポートします。
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports.add = add;
module.exports.subtract = subtract;Code language: JavaScript (javascript)代入では、関数名を括弧なしで使用し、module.exportsオブジェクトの個々のプロパティに割り当てます。
関数をエクスポートするときに、次のように異なる名前を使用できることに注意してください。
module.exports.sum = add;
module.exports.deduct = subtract;Code language: JavaScript (javascript)今のところ、エクスポートするときには同じ関数名を維持します。
3番目に、app.jsという新しいモジュールを作成し、mathモジュールをapp.jsモジュールにインポートします。
const math = require('./math');
console.log(math);Code language: JavaScript (javascript)モジュールをインポートするには、require()関数を使用します。require()関数は、モジュールへのパスを.js拡張子の有無にかかわらず受け入れます。
./は、math.jsモジュールがapp.jsモジュールと同じディレクトリにあることを示します。
コンソールには、mathが、addとsubtractの2つの関数をプロパティとして含むオブジェクトであることが示されています。
{ add: [Function: add], subtract: [Function: subtract] }Code language: JavaScript (javascript)最後に、mathオブジェクトを介してadd関数とsubtract関数を呼び出します。
// app.js
const math = require('./math');
let a = 20,
b = 5;
let result = math.add(a, b);
console.log(`${a} + ${b} = ${result}`);
result = math.subtract(a, b);
console.log(`${a} - ${b} = ${result}`);Code language: JavaScript (javascript)出力
20 + 5 = 25
20 - 5 = 15Code language: JavaScript (javascript)コードをより簡潔にするために、app.jsモジュールでオブジェクトの分割代入を次のように使用できます。
const { add, subtract } = require('./math');
// ...Code language: JavaScript (javascript)この構文では、require()関数によって返されるオブジェクトのプロパティをadd変数とsubtract変数に分割代入します。
これは、次と同じです。
// app.js
const math = require('./math');
const add = math.add,
subtract = math.subtract;
// ...Code language: JavaScript (javascript)デフォルトエクスポート
デフォルトエクスポートを使用すると、モジュールから単一の識別子 ( 変数、 関数、 オブジェクト、または クラス)をエクスポートできます。モジュールには、1つだけデフォルトのエクスポートを持つことができます。次の例を考えてください。
以下は、math.jsモジュールでデフォルトエクスポートを使用する方法を示しています。
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = add;Code language: JavaScript (javascript)この例では、add関数をプロパティではなくmodule.exportsオブジェクトに割り当てます。これはデフォルトエクスポートと呼ばれます。
app.jsモジュールでは、math.jsファイルからadd関数を直接インポートできます。
// app.js
const add = require('./math');
let a = 20,
b = 5;
let result = add(a, b);
console.log(`${a} + ${b} = ${result}`);Code language: JavaScript (javascript)出力
20 + 5 = 25Code language: JavaScript (javascript)デフォルトと名前付きのエクスポートの混合
まず、デフォルトと名前付きの両方のエクスポートを使用して、math.jsモジュールで識別子をエクスポートします。
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = add;
module.exports.subtract = subtract;Code language: JavaScript (javascript)次に、math.jsからadd関数とsubtract関数をapp.jsモジュールにインポートします。
const math = require('./math');
const add = math;
const subtract = math.subtract;
// ...Code language: JavaScript (javascript)モジュールラッパー関数の理解
モジュールを実行する前に、Node.jsは、そのモジュール内のすべてのコードを、次のような関数ラッパーでラップします。
(function(exports, require, module, __filename, __dirname) {
// Module code
});Code language: JavaScript (javascript)たとえば、実行前のmath.jsモジュールのコードは次のようになります。
(function (exports, require, module, __filename, __dirname) {
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports.add = add;
module.exports.subtract = subtract;
});Code language: JavaScript (javascript)これにより、Node.jsは、次の重要な目標を達成します。
- トップレベルの変数 (
var、let、およびconst) を、グローバルオブジェクトではなくモジュールにスコープします。 moduleやexportsなどのモジュール固有の変数を、グローバル変数のようにします。
exportsオブジェクトがmodule.exportsを参照していることに注意してください。
console.log(module.exports === exports); // trueCode language: JavaScript (javascript)同じモジュールを複数回インポートする
require()関数を使用して同じモジュールを複数回インポートすると、require()関数は、最初の呼び出しでのみモジュールを評価し、それをキャッシュに配置します。
後続の呼び出しからは、require()関数は、モジュールを再度実行するのではなく、キャッシュからのexportsオブジェクトを使用します。
次の例は、その仕組みを示しています。
まず、次のコードを持つdblogger.jsという新しいモジュールを作成します。
console.log('Connected to the DB');Code language: JavaScript (javascript)次に、app.jsでdblogger.jsモジュールを2回インポートします。
let dbLogger = require('./dblogger');
dbLogger = require('./dblogger');Code language: JavaScript (javascript)出力
DBLogger is loaded.Code language: JavaScript (javascript)この例では、メッセージ'DBLogger is loaded.'が2回ではなく1回だけ表示されることがわかります。これは、Node.jsがdblogger.jsを1回だけ評価したことを意味します。
概要
- CommonJSモジュールでは、Node.jsはJavaScriptファイルをモジュールとして扱います。
- モジュールで宣言された変数、定数、関数、クラスを含むすべての識別子は、グローバルスコープではなく、モジュールにスコープされます。
- 識別子をモジュールからエクスポートするには、
module.exportsオブジェクトのプロパティに割り当てます。 - Node.jsは、モジュールコードを実行する前に、モジュールラッパー関数でラップします。
- Node.jsはモジュールを1回だけ実行し、次の使用のために結果をキャッシュに配置します。