モジュール化とは?

JavaScriptのモジュール化とは、プログラムを機能ごとのファイルや部品に分割し、必要な部分を組み合わせて使用する設計方法です。
例えば、計算処理、ユーザー情報の管理、画面表示、通信処理などを別々のモジュールに分けることで、1つのファイルが必要以上に長くなることを防げます。
現在のJavaScriptでは、exportとimportを使うES Modulesが標準的なモジュール機能として利用されています。
モジュール化のメリット
コードを適切にモジュール化すると、開発や管理がしやすくなります。
再利用性が高まる
共通して使用する処理をモジュールとして分離すると、複数のファイルやプロジェクトから再利用できます。
例えば、金額を計算する関数や日付を整形する関数をモジュールにしておけば、同じ処理を何度も書く必要がありません。
保守しやすくなる
機能ごとにファイルが分かれていると、修正する場所を見つけやすくなります。
1つの機能を変更するときに、関係のないコードまで確認する必要が少なくなり、修正による影響範囲も把握しやすくなります。
コードの役割が明確になる
モジュールごとに役割を分けることで、それぞれのファイルが何を担当しているのか分かりやすくなります。
例えば、次のように分割できます。
math.js:計算処理user.js:ユーザー情報の管理api.js:サーバーとの通信main.js:各モジュールを組み合わせる処理
複数人で開発しやすくなる
機能ごとにファイルを分割しておくと、複数の開発者が異なるモジュールを担当できます。
同じファイルを同時に編集する機会が減るため、変更の競合も起こりにくくなります。
exportで機能を公開する
別のファイルから利用したい変数、関数、クラスなどには、exportを指定します。
名前付きエクスポート
複数の機能を公開する場合は、名前付きエクスポートを利用できます。
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export const taxRate = 0.1;
この例では、add、subtract、taxRateを別のモジュールから利用できるようにしています。
importで機能を読み込む
別のモジュールが公開した機能を利用するには、importを使用します。
// main.js
import { add, subtract, taxRate } from "./math.js";
console.log(add(10, 5)); // 15
console.log(subtract(10, 5)); // 5
console.log(taxRate); // 0.1
波括弧の中には、読み込みたい機能の名前を指定します。名前付きエクスポートを読み込む場合は、原則としてエクスポート時と同じ名前を使用します。
必要な機能だけを読み込む
名前付きエクスポートでは、公開されている機能の中から必要なものだけを読み込めます。
import { add } from "./math.js";
console.log(add(3, 7)); // 10
この例では、math.jsが公開している機能のうち、addだけを読み込んでいます。
default exportとは?
1つのモジュールから中心となる機能を1つだけ公開したい場合は、export defaultを使用できます。
// greet.js
export default function greet(name) {
return `こんにちは、${name}さん`;
}
デフォルトエクスポートを読み込む場合は、波括弧を使用しません。
// main.js
import greet from "./greet.js";
console.log(greet("Taro"));
デフォルトエクスポートは、読み込み側で任意の名前を付けられます。ただし、ファイルごとにデフォルトエクスポートできる値は1つだけです。
名前付きエクスポートとデフォルトエクスポートの違い
| 項目 | 名前付きエクスポート | デフォルトエクスポート |
|---|---|---|
| 記述方法 | export |
export default |
| 1ファイル内の数 | 複数指定できる | 1つだけ |
| import時の波括弧 | 必要 | 不要 |
| import時の名前 | 基本的に公開時と同じ名前 | 任意の名前を使用できる |
読み込む名前を変更する
名前付きエクスポートは、asを使って読み込み側の名前を変更できます。
import { add as calculateTotal } from "./math.js";
console.log(calculateTotal(8, 2)); // 10
同じ名前の変数や関数が存在する場合や、より分かりやすい名前に変更したい場合に便利です。
モジュール全体をまとめて読み込む
* asを使うと、モジュールが公開している機能を1つのオブジェクトとしてまとめて読み込めます。
import * as math from "./math.js";
console.log(math.add(10, 5)); // 15
console.log(math.subtract(10, 5)); // 5
console.log(math.taxRate); // 0.1
どのモジュールから読み込んだ機能なのかを明確にしたい場合に利用できます。
ブラウザでモジュールを読み込む
ブラウザでES Modulesを使用する場合は、script要素にtype="module"を指定します。
<script type="module" src="./main.js"></script>
type="module"を指定したスクリプトには、主に次の特徴があります。
- 自動的にstrictモードで実行される。
- HTMLの解析を妨げにくい形で実行される。
- モジュールごとに独立したスコープを持つ。
importやexportを使用できる。
モジュールのパスに関する注意点
ブラウザでローカルファイルを読み込む場合は、相対パスを明確に記述します。
import { add } from "./math.js";
./は現在のファイルと同じフォルダを表します。また、ブラウザでES Modulesを使用する場合は、通常、拡張子の.jsも省略せずに記述します。
開発環境によっては、HTMLファイルを直接開くのではなく、ローカルサーバーを通して表示する必要があります。
モジュールは独立したスコープを持つ
モジュール内で宣言した変数や関数は、自動的にグローバルスコープへ追加されません。
// settings.js
const apiUrl = "https://example.com/api";
console.log(apiUrl);
apiUrlはsettings.js内でのみ利用できます。別のモジュールから利用するには、明示的にexportする必要があります。
この仕組みにより、異なるファイルで同じ変数名を使用しても衝突しにくくなります。
モジュール化するときの分割単位
ファイルを細かく分ければよいとは限りません。モジュールは、関連する処理を1つの役割としてまとめることが重要です。
例えば、次のような単位で分割できます。
| モジュール | 担当する処理 |
|---|---|
validation.js |
入力値の検証 |
api.js |
サーバーとの通信 |
dom.js |
HTML要素の取得や更新 |
format.js |
文字列、数値、日付などの整形 |
1つのモジュールに複数の異なる役割を持たせすぎると、かえって保守しにくくなります。
モジュール化の注意点
- ファイルを細かく分割しすぎると、構成を把握しにくくなる。
- モジュール同士が強く依存すると、変更の影響が広がりやすくなる。
- 循環参照が発生しないように、依存関係を整理する。
- モジュール名や公開する関数名から役割が分かるようにする。
- 外部から使う必要がない変数や関数は
exportしない。
モジュール化のメリットのまとめ
| メリット | 説明 |
|---|---|
| 再利用性 | 共通する処理を別のファイルやプロジェクトでも利用できる。 |
| 保守性 | 変更箇所と影響範囲を把握しやすくなる。 |
| 可読性 | 機能ごとの役割やコードの構成が分かりやすくなる。 |
| 拡張性 | 既存の機能を保ちながら、新しいモジュールを追加できる。 |
| 名前の衝突防止 | モジュールごとに独立したスコープを利用できる。 |
| チーム開発 | 担当する機能を分けて並行して開発しやすくなる。 |
まとめ
- モジュール化とは、コードを機能や役割ごとに分割する設計方法である。
- 現在のJavaScriptでは、ES Modulesの
exportとimportを使用する。 - 名前付きエクスポートでは、1つのファイルから複数の機能を公開できる。
- デフォルトエクスポートは、1つのモジュールにつき1つだけ指定できる。
- ブラウザでは
script要素にtype="module"を指定する。 - モジュールは独立したスコープを持つため、変数名の衝突を防ぎやすい。
- 適切なモジュール化によって、コードの再利用性、保守性、可読性、拡張性が向上する。
- ファイルを細かく分けすぎず、役割に応じた単位で分割することが重要である。