import / export の基本
ES6(2015)で導入された ES Modules は、JavaScript の “モダンな書き方” を支える中心的な仕組みです。
その中核となるのが import / export です。
- ファイルを分割して整理したい
- 必要な機能だけを読み込みたい
- グローバル汚染を避けたい
- 再利用しやすいコードを書きたい
こうした目的のために、ES Modules は生まれました。
この回では、import / export の基本的な使い方を、実際のコード例を交えながら丁寧に解説します。
なぜ import / export が必要なのか
前回のモジュールスクリプトの基本で触れたように、従来の <script> にはいくつかの問題がありました。
- すべてがグローバルスコープに置かれる
- ファイル間の依存関係を明示できない
- 読み込み順に強く依存する
- 大規模化すると破綻しやすい
ES Modules は、これらの問題を解決するために設計されています。
export の基本
モジュールは、外部に公開したい機能を export することで、他のファイルから利用できるようになります。
export 方法には、大きく分けて下記の3つの記述方法があります。
1. 名前付きエクスポート(最も一般的)
export したい機能を個別に指定する方法です。
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
👉 複数の値を自由に export できます。
2. まとめてエクスポート
個別での export は行わず、最後にまとめて指定します。
function add(a, b) { return a + b; }
function sub(a, b) { return a - b; }
export { add, sub };
👉 export したい機能だけを後からまとめて記述するので、変更が容易です。
3. デフォルトエクスポート(1つだけ)
デフォルトの exportを指定します。(後述の import の記述方法が変わってきます。)
export default function greet(name) {
console.log(`Hello, ${name}`);
}
👉 デフォルト export は、そのモジュール(ファイル)につき 1 つだけ 定義できます。
export の注意点
- モジュールのトップレベルでしか使えない
- 名前付き
exportは複数 OK - デフォルト
exportは 1 つだけ
import の基本
export された機能や値を別のファイルから import して利用します。
import の記述には、下記のような記述方法があります。
1. 名前付き import
名前付きエクスポートされたものをインポートする時に指定します。
math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
main.js
import { add, PI } from "./math.js";
👉 export された名前をそのまま使います。
2. 別名(エイリアス)をつける
名前付きエクスポートされたものをインポートする時に指定するものですが、他のモジュールとの名前の衝突を避けたい場合などに指定します。
math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
main.js
import { add as plus } from "./math.js";
console.log(plus(1, 2));
👉 名前が衝突する場合に別名で定義できるので便利です。
3. デフォルト import
デフォルトエクスポートされたものを読み込む時に指定します。
greet.js
export default function greet(name) {
console.log(`Hello, ${name}`);
}
main.js
import greet from "./greet.js";
greet("kon");
👉 デフォルト export は {} を使いません。
4. 名前付き + デフォルトを同時に
デフォルトエクスポートされたものと名前付きエクスポートされたものを同時に読み込む時に指定します。
utils.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
export default function greet(name) {
console.log(`Hello, ${name}`);
}
main.js
import greet, { add } from "./utils.js";
5. モジュール全体をまとめて import
モジュールに定義されている export をまとめて読み込みたい時に指定します。
math.js
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
main.js
import * as math from "./math.js";
math.add(1, 2);
math.PI;
👉 モジュールを1つの名前空間としてまとめたいときに便利です。
import のパスの注意点
import でスクリプトファイルを指定する際は、 URL として判断される為、パスとして指定する必要があります。又、ブラウザは拡張子を自動補完しない為、拡張子の省略も不可です。
import "./utils.js"; // OK
import "/scripts/app.js"; // OK
import "./math.js"; // OK
import "utils.js"; // NG(相対パスが必要)
import "./math"; // NG(拡張子が必要)
import / export の実行タイミング
ES Modules の大きな特徴は、import が静的に解析されるという点です。
■ import はトップレベルでしか使えない
if (true) {
import "./a.js"; // ❌ エラー
}
👉 実行前に依存関係を確定する必要があるためです。
■ export もトップレベルのみ
モジュールの構造が明確になり、依存関係が静的に解析できます。
import / export の動作イメージ
┌──────────────────────────┐
│ math.js │
│──────────────────────────│
│ const x = 100 │
│ export function add() │
│ function sub() │
│ export const PI │
└─────────────┬────────────┘
│ import
▼
┌──────────────────────────┐
│ main.js │
│──────────────────────────│
│ import { add, PI } │
│ console.log(add(1, 2)) │
└──────────────────────────┘
- main.js が math.js を import
- math.js が最初に 1 回だけ実行される
- main.js は math.js の公開部分だけを利用できる
- 変数はグローバルに漏れない
👉 モジュールは「安全な箱」
👉 必要なものだけを外に出す(export)
👉 必要なものだけを取り込む(import)
よくあるエラーと対処法
1. 「Cannot use import statement outside a module」
→
<script type="module">を忘れている。
2. 「Failed to resolve module specifier」
→ パスが間違っている。(相対パス or 拡張子)
3. 「Unexpected token 'export'」
→ モジュールとして扱われていない。
4. CORS エラー
→
file://で開いている。(ローカルサーバーが必要)
まとめ
import/exportは ES Modules の中心機能import/exportには、用途に応じて、複数の記述方法があるimport/exportはトップレベルでのみ使用可能importにおいて、パスと拡張子は必須- モジュールは 1 度だけ実行される
- 小規模アプリならブラウザだけで十分、構造化したプログラミングが可能